diff options
Diffstat (limited to 'contrib/cvs/src')
80 files changed, 0 insertions, 120008 deletions
diff --git a/contrib/cvs/src/ChangeLog b/contrib/cvs/src/ChangeLog deleted file mode 100644 index 4e7a422..0000000 --- a/contrib/cvs/src/ChangeLog +++ /dev/null @@ -1,9664 +0,0 @@ -2008-03-10 Mark D. Baushke <mdb@gnu.org> - - * mkmodules.c, parseinfo.c: Update copyright. - - * parseinfo.c (parse_config): Add support for new - "IgnoreUnknownConfigKeys" configuration key. - * mkmodules.c (config_contents): Add text about the - "IgnoreUnknownConfigKeys" option. - * sanity.sh (config): Test that IgnoreUnknownConfigKeys=yes works. - -2008-01-30 Derek R. Price <derek@ximbiot.com> - - * update.c (join_file): Use local copy to detect deletion conflicts, - as opposed to the base revision. Restore freeing of rev2 to its - original location. Use simpler conflict message. - * sanity.sh: Update to compensate. - -2008-01-29 Derek R. Price <derek@ximbiot.com> - - * update.c (join_file): Remove trace that is no longer needed. - -2008-01-29 Derek R. Price <derek@ximbiot.com> - Paul Edwards <fight.subjugation@gmail.com> - - * update.c (join_file): Detect deletion conflicts. - * sanity.sh (join, join4): Adjusted for this fix. - (join8, join9): Add new tests for conflicts. - -2008-01-27 Mark D. Baushke <mdb@gnu.org> - - * filesubr.c (xreadlink): s/128/BUFSIZ/ avoid magic numbers. - - * client.c (start_rsh_server): Use CVS_SSH for the :extssh: - method or fall back to "ssh" as set using the --with-ssh flag to - configure. - - * client.h, log.c, main.c, recurse.c, root.c: Update copyright for - 2008. - -2008-01-24 Mark D. Baushke <mdb@gnu.org> - - * log.c (cvslog): New -n option to revert the -N switch. - (log_usage): Add -n to the help string. - * main.c (cmds[]): Add "blame" as a synonym for the - "annotate" command. - * sanity.sh (cvs-log): New tests for 'cvs log -N -n' validation. - (ann-10w1blame): Test the 'cvs blame' synonym for annotate. - (Patch suggested by "David O'Brien" <obrien@FreeBSD.org>) - - * edit.c (notify_check): Rename to... - (cvs_notify_check): ...this to avoid Mac OSX symbol conflicts. - * client.h, edit.h, recurse.c: Change all references. - - * client.c (start_rsh_server): Use RSH_DFLT not a hardcoded "rsh" - * root.c (parse_cvsroot): Fix parsing for the :extssh: method. - - * sanity.sh (expr_set_DASHDASH): Fix for non-POSIX expr - implementations. - (CVSROOTDIR): Use 'cvsrootdir' instead of 'cvsroot' to - avoid problems on case preserving and/or case insensitive - filesystems (e.g., HFS+). - (CVSROOT_DIRNAME): Use ${TESTDIR}/${CVSROOTDIR} instead of - ${TESTDIR}/cvsroot to avoid filesystem case sensitivity problems. - (crerepos-extssh): Clone of crerepos tests, but use the :extssh: - method. - -2007-12-19 Larry Jones <lawrence.jones@siemens.com> - - * client.c, import.c, lock.c, login.c, mkmodules.c, modules.c, - rcs.c, server.c: Fix gcc -Wall warnings. - -2007-12-16 Larry Jones <lawrence.jones@siemens.com> - - * rcs.c (HAVE_MMAP): Fall back to stdio if mmap fails. - -2007-12-13 Larry Jones <lawrence.jones@siemens.com> - - * rcs.c (rcsbuf_ftell): Avoid potential overflow. - -2007-12-12 Larry Jones <lawrence.jones@siemens.com> - - * vers_ts.c (time_stamp): Add warnings for [l]stat failures - other than no such file. - -2007-08-26 Derek Price <derek@ximbiot.com> - - * mkmodules.c (in_root): Rename to... - (in_repository): ...this. - -2007-08-26 Larry Jones <lawrence.jones@ugs.com> - - * mkmodules.c (in_root, init): Unmix declarations and code. - -2007-08-22 Derek Price <derek@ximbiot.com> - - * add.c (add): Check last component of argument paths instead of the - entire argument. - * sanity.sh (add-restricted): Test indirect paths to `CVS' dir with - add. - - * server.c (serve_init): Remove unnecessary argument to printf style - function. - - * mkmodules.c (in_root): New function. - (init): Verify that new roots are not created inside others. - * sanity.sh (init-3): New test for same. - -2007-08-16 Derek Price <derek@ximbiot.com> - - * root.c (root_allow_used): New function and... - * root.h (root_allow_used): ...its prototype. - * server.c (serve_root): Backport --allow-root test for `cvs server'. - * sanity.sh (server2-5, server2-6): New tests for the above. - -2007-06-18 Derek Price <derek@ximbiot.com> - - * client.c (send_repository): Don't attempt to send metadata from CVS - subdirectories when importing. - -2007-06-15 Derek Price <derek@ximbiot.com> - - * import.c (import): Check more carefully for files and directories - named "CVS". - * sanity.sh (import-1b): New test for same. - (import-2): Test files named "CVS", in addition to directories. - -2007-05-22 Larry Jones <lawrence.jones@ugs.com> - - * rcs.c (RCS_fully_parse): Include revision in error message. - -2007-05-07 Derek Price <derek@ximbiot.com> - - * mkmodules.c (init): Assert that the server is not active. - * server.c (serve_init): Send error message when the init command is - received from a client. - - * sanity.sh (*): Avoid using remote init. - (skip_always, localonly, restore_adm): New convenience functions. - -2007-03-08 Larry Jones <lawrence.jones@ugs.com> - - * rcs.c (findmagictag): Cast node->data before doing arithmetic - since it's now (void *). - -2007-03-05 Larry Jones <lawrence.jones@ugs.com> - - * rcs.c (RCS_delete_revs): When checking for tagged revisions, - include magic branch tags. - -2007-03-01 Larry Jones <lawrence.jones@ugs.com> - - * import.c (import_descend_dir): Correct error message. - * sanity.sh (pserver-3a): New test. - -2006-09-14 Derek Price <derek@ximbiot.com> - - * sanity.sh (server3, client2): New tests. - -2006-09-07 Derek Price <derek@ximbiot.com> - - [bug #17560] - * rcs.c (apply_rcs_changes): Improve comments. Restore repaired error - handling. - -2006-09-06 Larry Jones <lawrence.jones@ugs.com> - - * rcs.c (apply_rcs_changes): Improve linked list handling. Remove - unused variables and unreachable error handling code. Avoid unneeded - dynamic allocation of temp linevector. Minor stylistic code clean up. - -2006-09-06 Derek Price <derek@ximbiot.com> - - [bug #17560] - * rcs.c (apply_rcs_changes): Improve header block comment. Clean up - unused linevector on non-fatal error. - -2006-09-06 Derek Price <derek@ximbiot.com> - - [bug #17560] - * rcs.c (apply_rcs_changes): Remove an unecessary memcpy. Avoid some - other processing on error. - (linevector_delete): Remove - it's no longer used. - -2006-09-06 Mark D. Baushke <mdb@gnu.org> - - [bug #17560] - * rcs.c (apply_rcs_changes): Fix the merge algorithm from O(n^2) - to O(n). - (Based on a patch submitted by "Michael J. Smith" - <msmith@ideorlando.org>) - -2006-08-28 Derek Price <derek@ximbiot.com> - - * recurse.c (do_recursion): Remove misguided assertion. - * sanity.sh (dottedroot-3): Add test for the above. - (Thanks to report from Paul Eggert <eggert@CS.UCLA.EDU>.) - - [bug #17168] - * classify.c (Classify_File): Use T_PATCH for changed keywords instead - of T_CHECKOUT to conserver bandwidth. Don't sticky check when marking - files for update anyhow. - * sanity.sh: Update to compensate (s/^U /[UP] /). - -2006-08-25 Derek Price <derek@ximbiot.com> - - [bug #17168] - * classify.c (Classify_file): Mark files with potential keyword - substitution changes as needing update. - * sanity.sh: Update to compensate. - (keyword, keywordname, serverpatch): Update to compensate, removing - the last few "checksum failed" tests. - - * classify.c (Classify_File): Remove hacks which worked around checksum - failures from bug #17032. - -2006-08-24 Derek Price <derek@ximbiot.com> - - [bug #17032] - * update.c (patch_file): Correctly recreate client working files - containing the RCS `Name' keyword before generating patches. - * sanity.sh (keyword-23r): Merge with local case to compensate. - -2006-08-17 Larry Jones <lawrence.jones@ugs.com> - - * hash.h: Rename structs node and list to hashnode and hashlist - to avoid name clashes. - -2006-07-25 Mark D. Baushke <mdb@gnu.org> - - * login.c (free_cvs_password): New function to control freeing of - the static get_cvs_passwd() returned storage. - (login): Call it. - * cvs.h (free_cvs_password): Add prototype for it. - * client.c (auth_server): Call it. - [Alter the previous NetBSD coverity cid-3404 patch.] - -2006-07-11 Larry Jones <lawrence.jones@ugs.com> - - * log.c (log_usage): Fix misleading description of -b (it selects - revisions on the default branch *in addition to* revisions selected - with -r). - -2006-06-29 Derek Price <derek@ximbiot.com> - - * client.c (is_arg_a_parent_or_listed_dir): Strip trailing slashes from - dir name defore searching for it. Partially addresses TODO #205. - * sanity.sh (trailingslashes): Update to compensate. - -2006-06-28 Derek Price <derek@ximbiot.com> - - [bug #16961] - * login.c (get_cvs_password): Return copy of global variable. - (Patch from <mbarabas@redhat.com>.) - -2006-06-23 Larry Jones <lawrence.jones@ugs.com> - - * server.c (do_cvs_command): Remove unused variable. - -2006-06-22 Larry Jones <lawrence.jones@ugs.com> - - * mkmodules.c (modules_contents): Remove defunct -i option. - -2006-06-10 Derek Price <derek@ximbiot.com> - - * sanity.sh (conflicts4): Don't expect specific file permissions. Use - $PLUS. - -2006-06-08 Derek Price <derek@ximbiot.com> - - * sanity.sh (conflicts4): Test that the client honors Empty-conflicts. - - * server.c (requests): Add "Empty-conflicts" marker. - * client.c (send_fileproc): Send contents of all files with conflicts - unless the server can handle the conflict marker in the Entry. - - * sanity.sh (conflicts4): New tests. - (Original patch from Mark D. Baushke <mdb@gnu.org>.) - -2006-06-07 Mark D. Baushke <mdb@gnu.org> - - * modules.c (my_module): Remove unused variable xvalue. - [Fixes NetBSD coverity cid-705.] - -2006-05-31 Mark D. Baushke <mdb@gnu.org> - - * add.c (add): Fix memory leak. - [Fixes NetBSD coverity cid-3751.] - (add_directory): Fix memory leak. - [Fixes NetBSD coverity cid-3640.] - - * checkin.c (Checkin): Avoid possible NULL dereference. - [Fixes NetBSD coverity cid-2425.] - - * client.c (auth_server): Fix memory leak. - [Fixes NetBSD coverity cid-3404.] - - * commit.c (remove_file): Fix memory leak. - [Fixes NetBSD coverity cid-3752.] - - * rcs.c (RCS_checkin): Add assert (tip). - [Fixes NetBSD coverity cid-2424.] - -2006-05-26 Mark D. Baushke <mdb@gnu.org> - - * add.c (add): Do not leak memory. - [Fixes NetBSD coverity cid-2199.] - - * edit.c (onoff_fileproc): Do not leak memory. - [Fixes NetBSD coverity cid-2201.] - - * edit.c (onoff_filesdoneproc): Do not leak memory. - [Fixes NetBSD coverity cid-2202.] - - * lock.c (readers_exist): Add assert (lockdir). - [Fixes NetBSD coverity cid-2411.] - - * rcs.c (RCS_findlock_or_tip): Do not leak memory. - [Fixes NetBSD coverity cid-2198.] - - * rcs.c (RCS_getdate): Avoid possible NULL dereference. - [Fixes NetBSD coverity cid-2412.] - - * server.c (serve_sticky): Do not leak file descriptors. - [Fixes NetBSD coverity cid-2197.] - - * server.c (do_cvs_command): Do not leak memory. - [Fixes NetBSD coverity cid-2204.] - - * tag.c (add_to_val_tags): Do not leak memory. - [Fixes NetBSD coverity cid-2071.] - -2006-05-25 Derek Price <derek@ximbiot.com> - - * client.c (start_rsh_server): Default rsh client to RSH_DFLT. Remove - verbose comment attempting to justify the previous default. - -2006-05-24 Larry Jones <lawrence.jones@ugs.com> - - * sanity.sh: Add -v|--verbose option to echo test names. Clean - up help message. - Remove val-tags files for cleanup instead of truncating since the - truncation code doesn't work right on Solaris. Always use -f when - removing val-tags. - -2006-05-22 Derek Price <derek@ximbiot.com> - - * rcs.c (RCS_reparsercsfile, RCS_fully_parse, RCS_checkout, RCS_deltas, - RCS_getdeltatext, RCS_copydeltas): Verify input revision numbers. - (rcs6): Update to compensate. - - * sanity.sh (rcs6): New test. - -2006-05-16 Derek Price <derek@ximbiot.com> - - * main.c: Update copyright for 2006. - -2006-05-12 Mark D. Baushke <mdb@gnu.org> - - * log.c (log_expand_revlist): Add assert (r->first). It should - only be possible for both r->first == NULL && r->last == NULL - which would have been handled. - [Fixes NetBSD coverity cid-1063.] - - * server.c (do_cvs_command): Protect close (dev_null_fd) against - invalid fd value in error_exit. - [Fixes NetBSD coverity cid-1307.] - - * rcs.c (RCS_isdead): Assert that the first argument is not NULL. - [Fixes NetBSD coverity cid-1058.] - - * commit.c (checkaddfile): Do not dereference NULL on call to - error(). - [Fixes NetBSD coverity cid-1061.] - - * log.c (cvslog): Assert p->start && p->end instead of masking the - problem. - * server.c (server_updated): Assert findnode_fn results instead of - masking the problem. - - * add.c (add_directory): Revert previous change. The xstrdup() - function already deals a NULL argument. - * client.c (handle_mt): Ditto. - * entries.c (Entnode_Create): Ditto. - (Entries_Open): Ditto. - * logmsg.c (fmt_proc): Ditto. - * vers_ts.c (Version_TS): Ditto. - -2006-05-11 Mark D. Baushke <mdb@gnu.org> - - * add.c (add_directory): Protect tag from NULL dereference. - [Fixes NetBSD cid-1054.] - - * client.c (handle_mt): Deal with missing text argument. - [Fixes NetBSD cid-924.] - - * entries.c (Entnode_Create): Protect date, tag and ts_conflict - from possible NULL dereference. - [Fixes NetBSD coverity cid-994, cid-995, cid-1055, cid-1057.] - - * entries.c (Entries_Open): Protect dirtag and dirdate from - possible NULL dereference. - [Fixes NetBSD coverity cid-996.] - - * log.c (cvslog): Validate start and end args to - date_to_internet(). - [Fixes NetBSD coverity cid-2427 and cid-2428.] - - * logmsg.c (fmt_proc): Protect li->tag from NULL dereference. - [Fixes NetBSD coverity cid-997.] - - * vers_ts.c (Version_TS): Protect tag and vers_ts->tag from NULL - dereference. - [Fixes NetBSD coverity cid-1053.] - -2006-05-04 Mark D. Baushke <mdb@gnu.org> - - * filesubr.c (cvs_temp_file): Avoid keeping pointers to free()'d - storage laying around. - * commit.c (commit): Handle possible NULL filename values - returned from cvs_temp_file(). - * filesubr.c (cvs_temp_name): Ditto. - * import.c (import): Ditto. - * login.c (password_entry_operation): Ditto. - * logmsg.c (do_verify): Ditto. - * patch.c (patch_fileproc): Ditto. - [Fixes NetBSD coverity cid-2545.] - - * buffer.c (packetizing_buffer_output): Initialize outdata. - [Fixes NetBSD coverity cid-2474.] - - * server.c (server_updated): Check for NULL return from - findnode_fn(). [Fixes NetBSD coverity cid-1352.] - -2006-04-19 Larry Jones <lawrence.jones@ugs.com> - - * history.c (sort_order): Back out previous change - not needed. - -2006-04-15 Larry Jones <lawrence.jones@ugs.com> - - * history.c (sort_order): Add prototype. - * server.c (template_proc): Add prototype and make args const. - * update.c (RegisterMerge): Make static to match prototype. - -2006-04-07 Derek Price <derek@ximbiot.com> - - * client.c (strto_file_size): New function which checks for errors when - parsing protocol input. - (read_counted_file, update_entries, handle_mbinary): Use new function. - Remove FIXME. - (Thanks to a report from Brendan Harrison - <brendan.harrison@klocwork.com>.) - - * client.c (send_a_repository): Add assertion. - (Thanks to an incorrect report from Brendan Harrison - <brendan.harrison@klocwork.com>.) - -2006-04-06 Derek Price <derek@ximbiot.com> - - * filesubr.c (last_component, expand_wild), rcs.c (RCS_deltas, - RCS_rewrite), server.c (server_checked_in): Add assertions. - (Thanks to an incorrect report from Brendan Harrison - <brendan.harrison@klocwork.com>.) - -2006-03-31 Mark D. Baushke <mdb@gnu.org> - - * cvsrc.c (read_cvsrc): Deal with \r\n (DOS) line endings in - .cvsrc files. - -2006-03-07 Derek Price <derek@ximbiot.com> - - * tag.c (rtag_proc): Search the Attic when -F is used. - * sanity.sh (tests): Run death-rtag. - (death-rtag): Expect success. - - * sanity.sh (death-rtag): Add failing force tag move test. - -2006-03-06 Derek Price <derek@ximbiot.com> - - * tag.c (rtag_proc): Always search in the attic when -r is used. - - * sanity.sh (death-rtag): New test. - (Original report from C. Michael Pilato <cmpilato@collab.net>.) - -2006-03-01 Derek Price <derek@ximbiot.com> - - * sanity.sh: Set MALLOC_CHECK_ in hopes of exposing common memory - errors when CVS is linked with glibc 2.x. - -2006-02-27 Derek Price <derek@ximbiot.com> - - * lock.c (internal_lock): Back out previous change, we don't change - user visible output on stable unless absolutely necessary. - - * lock.c (internal_lock): Improve error message. - -2006-02-26 Derek Price <derek@ximbiot.com> - - * client.c (call_in_directory): Remove unneeded code. - * sanity.sh (toplevel-12): Compensate by failing to expect a redundant - error message. - -2006-02-24 Mark D. Baushke <mdb@gnu.org> - - * client.c (gzip_level): Move to... - * main.c (gzip_level): ...here. - (main): Revert previous change in '-z' argument processing and - remove CLIENT_SUPPORT ifdef/endif. - * sanity.h (crerepos-6a): Deal with --disable-client output. - - * main.c (main): Validate the gzip compression level for - --disable-client configurations. - -2006-02-13 Derek Price <derek@ximbiot.com> - - * server.c (do_cvs_command): Skip server_cleanup in the child process. - - * sanity.sh (sshstdio-6): Rewrite using more portable sed script. - -2006-02-02 Derek Price <derek@ximbiot.com> - - * sanity.sh (sshstdio): Attempt to ignore spurious SSH output. - - * main.c (main), release.c (release), server.c (do_cvs_command): Always - call the cleanup hooks before exit. - -2006-02-01 Derek Price <derek@ximbiot.com> - - * tag.c (add_to_val_tags): When a tag turns out to exist in the db when - it isn't expected, release the lock. - - * history.c (save_user, save_file, save_mod, read_hrecs): Avoid - overflow. - -2006-01-30 Derek Price <derek@ximbiot.com> - - * server.c (do_cvs_command): Set flow control pipe to blocking mode - before waiting for it to close. - (set_block_fd): New function. - (Original patch from Garrett Rooney <grooney@collab.net>.) - -2006-01-13 Larry Jones <lawrence.jones@ugs.com> - - * mkmodules.c (config_contents): Change SystemAuth to yes to match - the default value. Add missing newline in RereadLogAfterVerify. - -2006-01-09 Larry Jones <lawrence.jones@ugs.com> - - * commit.c (remove_file): Record correct revision in history file. - (Reported by Chris Reed <cr@progress.com>.) - -2005-12-07 Derek Price <derek@ximbiot.com> - - * client.c (start_server), root.c (method_names), root.h (CVSmethod): - Handle :extssh: as a kindness to Eclipse users. - (Suggestion from Joseph P. Skudlarek <Jskud@Jskud.com>.) - -2005-12-06 Mark D. Baushke <mdb@gnu.org> - - * buffer.c (stdio_buffer_shutdown): No longer assert() the - fstat(). Use error (0, ...) instead of error (1, ...) to avoid - infinite loops. (patch #4678) - Patch adapted from "Allan L. Bazinet" <allan.bazinet@gmail.com> - -2005-11-10 Larry Jones <lawrence.jones@ugs.com> - - * commit.c (commit): Complain about obsolete -n option if not in - server mode. - -2005-11-09 Derek Price <derek@ximbiot.com> - - * sanity.sh (pserver-4.2): Accept a "no such sytem user" message when - a root attempt is made. - -2005-09-30 Larry Jones <lawrence.jones@ugs.com> - - * expand_path.c (expand_path): Fix memory leaks. - -2005-09-29 Paul Eggert <eggert@CS.UCLA.EDU> - Derek Price <derek@ximbiot.com> - - * client.c (handle_m, handle_e): Remove incomplete workaround for - O_NONBLOCK problem; no longer needed because of the fix below. - (start_rsh_server): We need the O_NONBLOCK fix, so pass 'true' to - piped_child to enable the workaround. - * cvs.h (piped_child): New bool argument saying whether O_NONBLOCK - fix is needed. All uses changed. - * run.c (work_around_openssh_glitch): New function. - (piped_child): Use it if the fix is requested. Avoid call call to - vfork with undefined behavior. - -2005-09-26 Conrad T. Pino <Conrad@Pino.com> - - * rcs.c: Use "#ifdef HAVE_FSYNC" just like every where else. - -2005-09-25 Derek Price <derek@ximbiot.com> - - * rcs.c (rcs_internal_unlockfile): Fsync files before renaming them. - Patch from Rahul Bhargava <rahul@wandisco.com>. - -2005-09-24 Derek Price <derek@ximbiot.com> - - * update.c (merge_file): Check for RCS_checkout errors. - -2005-09-23 Larry Jones <lawrence.jones@ugs.com> - - * checkout.c (export_usage): Note that -r requires a tag. - -2005-09-22 Larry Jones <lawrence.jones@ugs.com> - - * patch.c (patch_usage): Document -k option. - -2005-09-22 Derek Price <derek@ximbiot.com> - - * classify.c (Classify_File): If a file had a conflict and the - timestamp hasn't changed, it still has a conflict. Add comment about - how T_MODIFIED could later turn out to have conflict markers and why - it should not be checked in this function. - * client.c (send_fileproc): Don't send contents for files known to have - conflicts unless this is for `cvs diff'. - * commit.c (check_fileproc): T_CONFLICT should be handled like - T_MODIFIED, since force could be requested. Simplify logic since - T_CONFLICT can now be trusted. - * cvs.h (file_has_conflict): Remove proto. - * rcs.c (RCS_Checkout): Comment noexec behavior in header block. - * server.c (serve_unchanged, serve_is_modified): Handle conflicts. - * status.c (status_fileproc): Trust T_CONFLICT to simplify. - * subr.c (file_has_conflict): Removed. - * update.c (update_fileproc): Trust T_CONFLICT. - (RegisterMerge): New function factored from... - (merge_file, join_file): ...these two functions. - * vers_ts.c (time_stamp_server): Handle = conflict timestamps in server - entdata. - * sanity.sh (files-12): Account for slight behavior improvement. - (status, conflicts, mwrap): Account for corrected behavior. - (join-readonly-conflict-10): Correct comment. - (binfiles-con1b): New test for correct behavior. - -2005-09-19 Derek Price <derek@ximbiot.com> - - * sanity.sh (modules5-8): Rename... - (modules5-8r): ...to this and comment Mac OS X failure. - Comment Solaris 9 failure below with a `FIXME?' tag. - - * sanity.sh: Remove previous hack in favor of setting TESTDIR on - Solaris (and Mac OS X) until problem is solved correctly. - -2005-09-15 Derek Price <derek@ximbiot.com> - - * sanity.sh: Use /bin/pwd to verify current dir since Solaris 9 is - sometimes resolving symlinked paths. - -2005-09-14 Derek Price <derek@ximbiot.com> - - * edit.c (edit_usage, unedit_usage, editors_usage), watch.c - (watch_usage, watchers_usage): Add quotes and reword for clarity and - consistency. - - * edit.c (edit_usage): Add missing syntax. Reword description for - clarity. Mention default behavior. - -2005-09-13 Derek Price <derek@ximbiot.com> - - * sanity.sh: Split $username into $username & $username8. Rename - $author as $anyusername. - -2005-09-12 Derek Price <derek@ximbiot.com> - - * sanity.sh (binfiles-con1b): Back out accidental addition. - - * sanity.sh (username): Cut $username down to 8 characters when longer, - since that is all that appears in output. - -2005-09-07 Derek Price <derek@ximbiot.com> - - Close <http://savannah.nongnu.org/bugs/?func=detailitem&item_id=14462>. - * rcs.c (RCS_parse): Free variable *after* using it for the last time. - -2005-09-06 Derek Price <derek@ximbiot.com> - - * rcs.c (RCS_putdtree): Remove unused variable. - -2005-09-06 Mark D. Baushke <mdb@gnu.org> - - Close <https://savannah.nongnu.org/bugs/?func=detailitem&item_id=14435>. - * rcs.c (RCS_putdtree): Avoid stack overflow which may be - possible with excessive recursive calls to RCS_putdtree(). - (Patch from Serg Masyutin.) - -2005-09-03 Derek Price <derek@ximbiot.com> - - * add.c (add_usage): Standardize usage message somewhat. - -2005-09-02 Larry Jones <lawrence.jones@ugs.com> - - * commit.c (checkaddfile): Improve error messages for lock_RCS failure. - * release.c (release): Improve error message for pclose failure. - - * root.h (struct cvsroot_s): Always declare isremote to simplify - other code. Simplify referencing code. - * root.c (new_cvsroot_t): Always initialize isremote. - * server.h: Always declare server_active to simplify other code. - Simplify referencing code. - * server.c: Always define server_active. - -2005-09-01 Derek Price <derek@ximbiot.com> - - * main.c, wrapper.c: Update links. - -2005-09-01 Derek Price <derek@ximbiot.com> - - * recurse.c: Update bug report email address. - -2005-08-30 Larry Jones <lawrence.jones@ugs.com> - - * import.c (import_descend): Lock repository directory during import. - -2005-07-12 Derek Price <derek@ximbiot.com> - - * buffer.c, buffer.h, client.h, expand_path.c, history.c, myndbm.h, - release.c: Add copyright notices. - -2005-07-11 Derek Price <derek@ximbiot.com> - - * buffer.c, buffer.h, client.h, expand_path.c, history.c, myndbm.h, - release.c: Update license notices. - -2005-06-22 Larry Jones <lawrence.jones@ugs.com> - - * vers_ts (Version_TS): Don't allow command line keyword expansion - modes to override binary mode. - * sanity.sh (): Tests for the above. - (Merged from trunk.) - -2005-06-06 Conrad T. Pino <Conrad@Pino.com> - - * cvs.h: Reverse patch committed 2005-05-27 by Conrad T. Pino. - * run.c: Reverse patch committed 2005-05-27 by Conrad T. Pino. - -2005-06-02 Derek Price <derek@ximbiot.com> - - * zlib.c (compress_buffer_shutdown_input): Don't attempt to read EOF - from the client during shutdown. It might never be sent. - * sanity.sh (abspath2): Test for this. - -2005-05-31 Derek Price <derek@ximbiot.com> - for Alexander Taler <alex@0--0.org> - - * rcscmds.c: Change type of call_diff_argc_allocated from int to - size_t, to match the prototype of run_add_arg_p(). This fixes a - bus error in OpenBSD 3.6 sparc64. - -2005-05-27 Conrad T. Pino <Conrad@Pino.com> - - * cvs.h: Replace "run_arg" function with "#define run_arg run_add_arg", - add "run_add_arg" prototype, change "piped_child" prototype to be same - as feature branch to reflect "(os2,src,windows-NT)/run.c" changes. - * run.c: Remove "run_arg" to synchronize with "../windows-NT/run.c". - Function "run_add_arg" scope was "static" and is now "extern" scope. - Synchronize "piped_child" function arguments with feature branch. - -2005-05-27 Derek Price <derek@ximbiot.com> - - * client.c (send_arg): Make arg const. - (send_option_string): Rename to... - (send_options): ...this and accept argc/argv in place of string. - * client.h: Update protos to match the changes to client.c. - * cvs.h (RCS_exec_rcsdiff, diff_exec): Update protos. - (run_add_arg_p, run_arg_free_p): New protos. - * diff.c (opts, opts_allocated): Replace with... - (diff_argv, diff_argc, diff_arg_allocated): ...these. - (add_diff_args): New convenience function. - (diff): Use new constructs and APIs. - * patch.c (patch_fileproc, RCS_checkin, RCS_delete_revs), rcscmds.c - (call_diff_add_arg, call_diff_setup, RCS_merge, RCS_exec_rcsdiff, - diff_exec, RCS_output_diff_options), update.c (patch_file): Use new - APIs. - * run.c (run_add_arg_p, run_arg_free_p): New functions. - (run_argc_allocated): Make size_t. - (run_setup, run_add_arg): Use new functions. - * sanity.sh: Accomodate above changes. - (rcslib-diffrgx-3): Slip in test for space splitting. - -2005-05-02 Derek Price <derek@ximbiot.com> - - Remove unnecessary level of indirection. - * lock.c (L_HISTORY_LOCK, L_VAL_TAGS_LOCK): Remove macros. - (internal_lock, internal_clear_lock): Accept lock as argument. - (history_lock, clear_history_lock, val_tags_lock, clear_val_tags_lock): - Replace old macro arg with an actual lock pointer. - -2005-05-02 Derek Price <derek@ximbiot.com> - - * lock.c (internal_lock, internal_clear_lock): Add protos. - (history_lock, val_tags_lock): Return the chartered true/false status. - -2005-05-02 Derek Price <derek@ximbiot.com> - - * cvs.h (CVSHISTLCK): Rename macro to... - (CVSHISTORYLCK): ...this. - (CVSVALTAGSLCK): New macro. - (val_tags_lock, clear_val_tags_lock): New functions. - * lock.c (global_val_tags_lock): New global. - (Lock_Cleanup): Clean up after val-tags lock if necessary. - (L_HISTORY_LOCK, L_VAL_TAGS_LOCK): New local macros. - (internal_lock, internal_clear_lock, val_tags_lock, - clear_val_tags_lock): New functions. - (history_lock, clear_history_lock): Use new internal functions. - * tag.c (is_in_val_tags, add_to_val_tags): New functions using the - write-lock for val-tags and factored from... - (tag_check_valid): ...this function. - * sanity.sh (lockfiles-22): Add val-tags lock test. - -2005-04-28 Derek Price <derek@ximbiot.com> - - * cvs.h (history_lock, clear_history_lock): New protos. - * lock.c (struct lock): Add lockdirname. - (global_history_lock): New global. - (global_read_lock): Initialize. - (lock_name): Handle const args. - (lock_simple_remove): Factor out code in favor of clear_lock call. - (set_lock): Handle variable lockdirname. - (lock_filesdoneproc): Set new lockdirname. - (history_lock, clear_history_lock): New functions. - (clear_lock): Avoid segfault on missing lock. - (Lock_Cleanup): Clean up history locks when necessary. - * history.c (history_write): Use new lock. - * sanity.sh (lockfiles-20): Test new lock. - -2005-04-28 Derek Price <derek@ximbiot.com> - - * sanity.sh (lockfiles): Port some locking tests over from 1.12.x. - -2005-04-28 Derek Price <derek@ximbiot.com> - - * lock.c (clear_lock): Improve comment. - -2005-04-28 Derek Price <derek@ximbiot.com> - - * lock.c (struct lock): Store lockdir name. - (masterlock): Remove global. - (remove_lock_files, clear_lock, set_lock): Update to compensate. - -2005-04-20 Derek Price <derek@ximbiot.com> - - * sanity.sh (rcs5): Minor cosmetic change. - -2005-04-20 Derek Price <derek@ximbiot.com> - - * sanity.sh (tests): Add rcs4. - (rcs5): Add comments. - -2005-04-20 Derek Price <derek@ximbiot.com> - - * rcs.c (expand_keywords): Avoid buffer overflow. - (Original patch from Stewart Brodie <stewart@eh.org>.) - - * sanity.sh (rcs5): New tests for the above. - -2005-03-17 Derek Price <derek@ximbiot.com> - - * login.c (password_entry_parseline): Avoid using uninitialized - variable. - * rcs.c (RCS_deltas): Avoid buffer overflow. - (RCS_checkout): Avoid using uninitialized loglen. - * patch.c (patch_fileproc): Free original pointer, not one that may - have been incremented. - (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.) - -2005-03-17 Derek Price <derek@ximbiot.com> - - * commit.c (checkaddfile): Avoid dereferencing a NULL pointer in - response to a rare error. - * admin.c (admin_fileproc), log.c (log_expand_revlist), mkmodules.c - (checkout_file), rcs.c (RCS_getdate, RCS_deltas, RCS_findlock_or_tip, - RCS_tag2rev): Avoid dereferencing NULL pointer. - (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.) - -2005-03-17 Derek Price <derek@ximbiot.com> - - * rcs.c (RCS_reparsercsfile): Avoid memory leak. - (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.) - -2005-03-17 Derek Price <derek@ximbiot.com> - - * log.c (log_expand_revlist): Suppress message and not error handling - when really_quiet. - -2005-03-17 Derek Price <derek@ximbiot.com> - - * client.c (call_in_directory): Put function call after var decls. - -2005-03-16 Derek Price <derek@ximbiot.com> - - * client.c (call_in_directory), commit.c (commit_filesdoneproc), log.c - (log_expand_revlist, log_version), logmsg.c (logfile_write), modules - (my_module), no_diff.c (No_Difference), parseinfo.c (Parse_Info), rcs.c - (RCS_deltas, RCS_checkin, RCS_addbranch, do_locks, do_symbols), - rcscmds.c (RCS_merge), root.c (parse_cvsroot, normalize_cvsroot), - update.c (merge_file): Verify assumptions via assertions. - (Thanks to (probably) incorrect reports from Alen Zukich - <alen.zukich@klocwork.com>.) - -2005-03-16 Derek Price <derek@ximbiot.com> - - * server.c (create_adm_p, serve_entry), tag.c (rtag_proc): Avoid memory - leaks. - (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.) - -2005-03-15 Mark D. Baushke <mdb@cvshome.org> - - * history.c (select_hrec): Avoid possible memory leak. - -2005-03-15 Derek Price <derek@ximbiot.com> - - * patch.c (patch_proc): Avoid memory leak. - (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.) - -2005-03-11 Mark D. Baushke <mdb@cvshome.org> - - * modules.c (my_module): Protect against free (NULL) code path. - -2005-03-11 Derek Price <derek@ximbiot.com> - - * annotate.c (rannotate_proc), fileattr.c (fileattr_write), rcs.c - (RCS_deltas), server.c (check_repository_password), update.c (update): - Avoid memory leaks. - (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.) - -2005-03-09 Derek Price <derek@ximbiot.com> - - * add.c (add, add_directory), buffer.c (allocate_buffer_datas), - client.c (update_entries), commit.c (checkaddfile), entries.c - (Entries_Open), fileattr.c (fileattr_read), ignore.c (ign_add), - import.c (import), main.c (main), parseinfo.c (parse_config), rcs.c - (RCS_reparsercsfile, RCS_getbranchpoint, RCS_checkout, - RCS_delete_revs, apply_rcs_changes): Avoid memory leaks. - (Thanks to report from Alen Zukich <alen.zukich@klocwork.com>.) - - * hardlink.c, hardlink.h: Avoid compiling entire contents of these - files w/o preserve permissions support. - -2005-03-09 Mark D. Baushke <mdb@cvshome.org> - - * history.c (history, save_file): Cleanup the API to match the - comments. - -2005-02-27 Jim Meyering <jim@meyering.net> - - * login.c (password_entry_operation): Exit nonzero when - failing to close a just-appended-to .cvspass file. - -2005-02-26 Larry Jones <lawrence.jones@ugs.com> - - * release.c (release): Remove unneeded code. - -2005-02-22 Derek Price <derek@ximbiot.com> - - * edit.c: Load watch settings before setting new ones with - `cvs watch on/off'. - (Original patch from Jim Hyslop <jhyslop@ieee.org>.) - - * sanity.sh (watch6): New tests for same. - (Outline from Jim Hyslop <jhyslop@ieee.org>.) - -2005-02-21 Mark D. Baushke <mdb@cvshome.org> - - * import.c (import): Avoid using assert with side effects it may - be configured away using NDEBUG. - (Patch from Frank Hemer <frank@hemer.org>.) - -2005-02-08 Derek Price <derek@ximbiot.com> - - * build_src.com: Build stack.c on VMS. - (Suggestion from Piet Schuermans <pschuermans@mac.com>.) - -2005-02-01 Larry Jones <lawrence.jones@ugs.com> - - * log.c (log_fileproc, log_expand_revlist): Add support for BASE tag. - * sanity.sh (log): New tests for above. - -2005-01-31 Derek Price <derek@ximbiot.com> - - * main.c: Update year in copyright notice to match GNU standards. - * sanity.sh (version-1): Update to match. - -2005-01-31 Derek Price <derek@ximbiot.com> - - * main.c: Rephrase --version message. - * sanity.sh (version-1): Update to match. - -2005-01-31 Derek Price <derek@ximbiot.com> - - * Makefile.am, add.c, admin.c, annotate.c, checkin.c, checkout.c, - classify.c, commit.c, create_adm.c, cvs.h, cvsrc.c, diff.c, entries.c, - find_names.c, hash.c, hash.h, history.h, import.c, lock.c, log.c, - login.c, logmsg.c, main.c, mkmodules.c, modules.c, myndbm.c, no_diff.c, - parseinfo.c, patch.c, rcs.c, rcs.h, rcscmds.c, recurse.c, remove.c, - repos.c, root.c, root.h, server.h, stack.c, stack.h, status.c, subr.c, - tag.c, update.c, vers_ts.c, version.c: Update copyright notices. - -2005-01-29 Derek Price <derek@ximbiot.com> - - * log.c (log_usage): Add note about using -S with revision info - supression and selection. - (Suggestion from Dan Peterson <dbpete@aol.com>.) - -2004-12-19 Larry Jones <lawrence.jones@ugs.com> - - * expand_path.c (expand_path): Rewrite using offsets instead of - pointers to simplify and avoid reallocation bugs. - (Inspired by Jeremy Bopp <jeremy@motive.com>.) - -2004-12-09 Derek Price <derek@ximbiot.com> - - * sanity.sh (tests): Add modules7. - -2004-12-09 Derek Price <derek@ximbiot.com> - - * sanity.sh (modules7): New test group. - (Based on a patch from Mark D. Baushke <mdb@cvshome.org>, based on a - report from Richard Verhoeven <Richard_Verhoeven@WestLB.de>.) - -2004-11-18 Mark D. Baushke <mdb@cvshome.org> - - * checkout.c (checkout_proc): Passing the repository to - tag_check_valid seems to stop the assertion failure in recurse.c - do_recursion. - * sanity.sh (basic2-21a): Removed. - (basic2-21b): Fixed. - -2004-11-17 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (basic2-21a): The val-tags file should have - at least 'rtagged-by-head y' in it. - (basic2-21b): New test showing a cvs bug when val-tags - is not properly updated. - (Report from "John Elgin" <John@JCElgin.com>.) - -2004-11-17 Mark D. Baushke <mdb@cvshome.org> - - * client.c (handle_m, handle_e): Winsock is returning - SOCK_ERRNO == WSAENOTSOCK for select() problems and not - setting errno. Do not bother with printing an error from a - select() that is not returning an non-zero errno. - (Report from Conrad T. Pino <Conrad@Pino.com>.) - -2004-11-10 Derek Price <derek@ximbiot.com> - - * sanity.sh: Maintain pass/skip/warn status and output at end. - (usage): Note new functionality of -e. - (warn): New function. - (verify_tmp_empty): Warn instead of failing. Delete turds if warn() - doesn't exit. - -2004-11-10 Derek Price <derek@ximbiot.com> - - * sanity.sh (verify_tmp_empty): New function. - (dotest_internal_*): Call verify_tmp_empty as needed. - -2004-11-09 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh: Backport find_tool changes from 1.12.9.1. - (SEARCHPATH): New list of PATH directories to search. - (Which): Use $SEARCHPATH. Support -a switch. - (badtools,set_bad_tool,is_bad_tool): Keep track of tools that do - not work for us. - (version_test): Obtain the version of tools under test if - possible. - (tool_find): Rewrite. API changed to allow a list of - tests to be used against a list of possible command names found on - the SEARCHPATH. - (id_tool_test): Check that 'id -u' and 'id -un' work. - (expr_tooltest1): Check for NextStep 3.3 expr bug. - (expr_tooltest2): Check for SunOS expr multi-line pattern bug. - (expr_create_bar): Create a test file for expr testing. - (expr_tooltest3): Use it and test for big multi-line identity - matches. - (expr_set_ENDANCHOR): Find and set the right value for ENDANCHOR. - (expr_set_DOTSTAR): Find and set the right value for DOTSTAR. - (expr_tooltest_DOTSTAR): Ensure that DOTSTAR works with big - matches. - (tr_tooltest1): Verify that tr handles NUL bytes. - (awk_tooltest1): Verify that awk the BEGIN clause works properly. - (awk_tooltest2): Verify that print %c format item works properly. - -2004-11-02 Mark D. Baushke <mdb@cvshome.org> - - * filesubr.c (MAXSIZE): New macro. - (xreadlink): Ensure initial buffer size does not exceed MAXSIZE. - Avoid cast. If readlink fails with buffer size just under MAXSIZE, - try again with MAXSIZE. - -2004-11-02 Mark D. Baushke <mdb@cvshome.org> - - * filesubr.c (xreadlink): AIX and HP-UX readlink() returns ERANGE - when there is not enough room in the buffer. - -2004-11-01 Derek Price <derek@ximbiot.com> - - * sanity.sh (rcslib): Fix typo in path. - -2004-11-01 Derek Price <derek@ximbiot.com> - - * sanity.sh (rcslib): Test a link to a path longer than 128 - characters. - -2004-10-29 Derek Price <derek@ximbiot.com> - - * filesubr.c (xreadlink): Make sure allocation is tried once at the - maximum buffer size. Protect against overflow. - -2004-10-29 Mark D. Baushke <mdb@cvshome.org> - - * filesubr.c (SIZE_MAX, SSIZE_MAX): Use #include "xsize.h" instead. - (xreadlink): Use xrealloc instead of xmalloc/free. - -2004-10-29 Mark D. Baushke <mdb@cvshome.org> - - * filesubr.c (SIZE_MAX, SSIZE_MAX): New constants. - (xreadlink): Deal with symlinks longer than 127 bytes. - (Problem reported as issue 190 by Gottfried Ganssauge - <gotti@cvshome.org>.) - -2004-10-28 Mark D. Baushke <mdb@cvshome.org> - - * release.c (release): Allow builds of cvs with --disable-server - --disable-client both used for local installation configuration. - * root.c (Name_Root): Ditto. - * update.c (checkout_file): Ditto. - (Problem reported by Jean Olivier Caron <jecar@mlab.t.u-tokyo.ac.jp>.) - -2004-10-27 Mark D. Baushke <mdb@cvshome.org> - - * cvs.h (RCS_FLAGS_USETIME): New flag. - * rcs.c (RCS_checkin): Add citime argument. - * rcs.h (RCS_checkin): Ditto. - * checkin.c (Checkin): Pass new RCS_checkin argument. - * commit.c (remove_file, checkaddfile): Ditto. - * import.c (add_rev): Ditto. - - * sanity.sh (tagdate): Delete tagdate-19b as an incorrect test. - -2004-10-27 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (tagdate): Provide more output. - -2004-10-26 Mark D. Baushke <mdb@cvshome.org> - - * commit.c (checkaddfile): Create a dead version for a new file - added to a branch. Fixes FIXCVS for tagdate tests. - * sanity.sh (tagdate): Update to expect correct results. - (death2, branch-after-import, join, ignore-on-branch): Ditto. - -2004-10-26 Derek Price <derek@ximbiot.com> - - * client.c (connect_to_gserver): Avoid truncating error messages from - the GSSAPI server. - (Report from Dan Peterson <dbpete@aol.com>.) - -2004-10-26 Derek Price <derek@ximbiot.com> - - * sanity.sh (import-quirks): Test an even branch number. - -2004-10-25 Derek Price <derek@ximbiot.com> - - * import.c (import): Repair regex for regressions introduced in last - commit. - * sanity.sh (import-quirks): Test a few branch numbers import shouldn't - have a problem with. - -2004-10-25 Derek Price <derek@ximbiot.com> - - * import.c (import): Anchor and simplify branch verification regex. - * sanity.sh (import-quirks): Test another pattern that should fail. - -2004-10-25 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (tagdate): Added some additional tests and FIXCVS - comments for dealing properly with a 'cvs add' of a file to - a branch that already exists on the mainline. - (Problem reported by Renny Barrett <rbarrett@curamsoftware.com>.) - - * sanity.sh (getrlogdate): New shell function. - (tagdate-{13,14,16}): Use it to avoid 'sleep 60' by using - the exact 1.1.4.1 timestamp for tagdate-14 and tagdate-16. - -2004-10-22 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (tagdate): Fix typo. - -2004-10-19 Derek Price <derek@ximbiot.com> - - * add.c (add): Avoid attempting to resurrect a dead rev 1.1. - * sanity.sh (resurrection): Add test for the above. - (Report from Dan Peterson <dbpete@aol.com>.) - -2004-10-14 Derek Price <derek@ximbiot.com> - - * import.c (import): Verify branch specifications more thoroughly. - * sanity.sh (importb): Adapt to new error message. - (import-quirks): New test. - -2004-10-04 Derek Price <derek@ximbiot.com> - - * cvs.h (CVSROOT_DFLT): Undef rather than defining to NULL. - * main.c (main): Untangle parsing of CVSROOT, eliminating several - variables in the process. Simplify xmalloc/sprintf with asnprintf. - -2004-10-01 Mark D. Baushke <mdb@cvshome.org> - - * main.c (main): Initialize CVSroot before it is used. - (Report and patch by Martin Neitzel <neitzel@sco.gaertner.de>.) - * sanity.sh (status): Test it. - -2004-09-25 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (parseroot2): Correct two test names. Restore CVSROOT. - - * sanity.sh (parseroot2): Expand dokeep inline. - -2004-09-24 Derek Price <derek@ximbiot.com> - - * sanity.sh (tests): Add parseroot2. - -2004-09-24 Derek Price <derek@ximbiot.com> - - * sanity.sh (parseroot2): New test for root parsing consistency. - (Original patch from Alexander Taler <dissent@cvshome.org>.) - - * cvs.h (Name_Root, free_cvsroot_t, parse_cvsroot, local_cvsroot, - Create_Root, root_allow_add, root_allow_free, root_allow_ok): Move - these protos to... - * root.h: ...here. - * client.c (arg_should_not_be_sent_to_server), recurse.c - (start_recusrion, do_recursion): Use new Name_Root API. - * main.c (current_root): Remove global. - (set_root_directory): Set current_parsed_root directly. - (main): Use new Name_Root API. Restore deletion of root directories - list. - * root.c (Name_Root): Return a parsed cvsroot_t rather than a string. - -2004-09-23 Derek Price <derek@ximbiot.com> - - * sanity.sh (depends_on_ssh, sshstdio): Don't use skip() to skip - remote-only tests. - -2004-09-23 Mark D. Baushke <mdb@cvshome.org> - - * server.c (cvs_output, cvs_output_binary): fflush (stderr) - here to avoid problems with 'cvs status 2>&1'. - (Report by Frank Hemer <frank@hemer.org>.) - -2004-09-23 Derek Price <derek@ximbiot.com> - - * sanity.sh (crerepos, sshstdio): Minor modifications to make use of - the new depends_on_?sh API. - -2004-09-23 Derek Price <derek@ximbiot.com> - - * sanity.sh: Accept new -e option to interpret non-fatal calls to skip - as errors. - (skip, depends_on_rsh, depends_on_ssh): New functions. - -2004-09-12 Mark D. Baushke <mdb@cvshome.org> - - * rcs.c (RCS_checkout): Allow noexec to do checkouts when - server_active is true. - * sanity.sh (join7): Test above change (fixes a FIXCVS). - -2004-09-08 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (join7): Fix if-then-else conditional. - - * server.c (server_updated): Deal with cvs -n update -jt1 -jt2 - "protocol error: uncounted data discarded" problem. - * sanity.sh (join7): New test for this case. - -2004-08-24 Derek Price <derek@ximbiot.com> - - * recurse.c (start_recursion): Don't shorten //. to / (use //). - -2004-08-24 Derek Price <derek@ximbiot.com> - - * recurse.c (start_recursion): Strip trailing CWD indirections on - repository. - * sanity.sh (rstar-toplevel): Update to account for new behavior. - (Report from Dan Peterson <dbpete@aol.com>.) - -2004-08-24 Mark D. Baushke <mdb@cvshome.org> - - * recurse.c (do_recursion): Correct test for calling - server_pause_check to occur when locktype != CVS_LOCK_WRITE. - (Patch suggested by Ian Lance Taylor <ian@wasabisystems.com> - in bug#198). - -2004-08-24 Derek Price <derek@ximbiot.com> - - * rcs.c (translate_symtag): Prevent infinite loop. - * tag.c (tag_check_valid): Check tag syntax before searching for tags. - * sanity.sh (tag-space): Some tests for the above. - (Report from Dan Peterson <dbpete@aol.com>.) - -2004-08-24 Mark D. Baushke <mdb@cvshome.org> - - * ignore.c (ignore_directory): Include the terminating NUL - character in the directory name comparison to avoid matching - substrings of directories by accident. - (Report and suggested fix from James E Wilson - <wilson@specifixinc.com>.) - * sanity.sh (modules4): Add some more tests testing the above - change. - -2004-08-17 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (sshstdio): Fix comment typo plus gratuitous - reformatting. - - * client.c (handle_m): Workaround to deal with stdio getting put - into non-blocking via redirection of stderr and interaction with - ssh on some platforms. On those boxes, stdio can put stdout - unexpectedly into non-blocking mode which may lead to fwrite() or - fflush() failing with EAGAIN, but cvs not checking for the error. - (Patch suggested by Frank Hemer <frank@hemer.org>.) - - * client.c (handle_e): Similar fix for stderr. - * sanity.sh (sshstdio): New test for non-blocking stdio via ssh. - -2004-08-11 Derek Price <derek@ximbiot.com> - - * sanity.sh (basicc): Work around a problem in Linux 2.2 & Bash 2.05b - which prevents a `cd ..' from a deleted directory from working. - (Original patch from Matthew Ogilvie <mmo9317bd@mailcan.com>.) - -2004-06-22 Derek Price <derek@ximbiot.com> - - * wrapper.c: Add explicit "void" return type to "wrap_clean_fmt_str" - definition. - (Patch from Conrad T. Pino <Conrad@Pino.com>.) - -2004-06-09 Derek Price <derek@ximbiot.com> - - * commit.c, filesubr.c, history.c, server.c, wrapper.c: Various - security fixes. - (Original patch from Stefan Essler <s.esser@e-matters.de> & Sebastian - Krahmer <krahmer@suse.de>.) - - * cvs.h: Include xsize.h. - -2004-06-09 Derek Price <derek@ximbiot.com> - - * server.c (serve_entry, serve_is_modified, serve_unchanged): Protect - against malformed entries. - * sanity.sh (server): Tests for same. - -2004-06-07 Larry Jones <lawrence.jones@ugsplm.com> - - * sanity.sh (basica): More tests for string-based revision inc. - -2004-06-04 Larry Jones <lawrence.jones@ugsplm.com> - - * subr.c (increment_revnum): Rewrite ala RCS to work directly on - the string rather than converting to int to avoid overflow. - * sanity.sh (basica): New tests for above, update others to match. - -2004-05-19 Derek Price <derek@ximbiot.com> - - * server.c (serve_unchanged, serve_is_modified): Overwrite existing - data in timefields. Fixes CAN-2004-0396. - -2004-05-14 Derek Price <derek@ximbiot.com> - - * subr.c (file_has_conflict), vers_ts.c (time_stamp_server): Don't - require '=' to be the only character here, as this is potentially - destabilizing. - -2004-05-14 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (trailingslashes): During cleanup remove topfile,v to - avoid problems in later tests (editor-1). - -2004-05-13 Derek Price <derek@ximbiot.com> - - * sanity.sh (trailingslashes): Note TODO item #205 in the comment. - -2004-05-13 Derek Price <derek@ximbiot.com> - - * sanity.sh (trailingslashes): New tests to expose a bug in CVS when - paths are specified with trailing slashes. This relates to TODO #205. - -2004-05-12 Derek Price <derek@ximbiot.com> - - * subr.c (file_has_conflict), vers_ts.c (time_stamp_server): Only - special case "=" when it is the only character in a timestamp field. - Gratuitous reformatting. - * vers_ts.c (time_stamp_server): Check for NULL in a consistent manner. - Gratuitous reformatting. - -2004-05-10 Derek Price <derek@ximbiot.com> - - * sanity.sh (top-level): Rename to... - (rstar-toplevel): ...this for clarity. - -2004-05-10 Derek Price <derek@ximbiot.com> - - * sanity.sh (dirs2-10ar): Remove unnecessary empty argument. - -2004-05-02 Larry Jones <lawrence.jones@ugsplm.com> - - * log.c (log_expand_revlist): Suppress warnings if really_quiet. - -2004-05-07 Derek Price <derek@ximbiot.com> - - * sanity.sh (basica): Remove unnecessary empty arguments. - -2004-05-07 Derek Price <derek@ximbiot.com> - - * cvs.h (fopen_case): Remove obsolescent prototype. - -2004-05-05 Derek Price <derek@ximbiot.com> - - * sanity.sh: Wait a second and retry if cvs-serv* directories are - discovered to avoid race conditions on some systems. - (Patch from Pavel Roskin <proski@gnu.org>.) - -2004-05-05 Derek Price <derek@ximbiot.com> - - * commit.c: Some gratuitous reformatting. - -2004-05-04 Derek Price <derek@ximbiot.com> - - * update.c: Some gratuitous reformatting. - -2004-05-04 Derek Price <derek@ximbiot.com> - - * add.c (add): Remove obsolete FIXME comment. - (*): Some gratuitous reformatting. - -2004-04-26 Derek Price <derek@ximbiot.com> - - * client.c (start_rsh_server): Don't rely on GNU argument processing - capabilities in the RSH command. - (Report from Mark Andrews <Mark_Andrews@isc.org>.) - -2004-04-19 Derek Price <derek@ximbiot.com> - - * ignore.c: Gratuitous reformatting. - -2004-04-11 Derek Price <derek@ximbiot.com> - - * client.c (call_in_directory): Check paths the server sends us to make - sure they are within a sandbox the user requested be updated. - (is_valid_client_path, path_list_prefixed): New functions. - -2004-04-11 Derek Price <derek@ximbiot.com> - - * modules.c (do_module): Don't allow up-level references in paths to - step out of the repository. - * sanity.sh (multiroot3): Update tests and add a few more. - -2004-04-07 Derek Price <derek@ximbiot.com> - - * sanity.sh (parseroot): Replace hard path with $HOME. - -2004-04-07 Derek Price <derek@ximbiot.com> - - * sanity.sh (parseroot): s/oberon/$username/. - -2004-04-07 Derek Price <derek@ximbiot.com> - - * client.c (start_tcp_server): Use xstrdup rather than - xmalloc(strlen)/strcpy. - -2004-04-07 Derek Price <derek@ximbiot.com> - - * root.c (parse_cvsroot): Ignore method options. - * sanity.sh (parseroot): Verify that method options are ignored. - -2004-04-06 Derek Price <derek@ximbiot.com> - - * root.h (cvsroot_t): Move username, password, hostname, port inside - CLIENT_SUPPORT ifdefs. - * buffer.c, root.c, server.c: Add #ifdefs as necessary so that this - will compile without client support and the root.h change. Some - gratuitous restyling. - -2004-04-06 Derek Price <derek@ximbiot.com> - - * log.c, tag.c: Gratuitous restyling. - -2004-04-04 Derek Price <derek@ximbiot.com> - - * filesubr.c (isabsolute): Move... - * subr.c: ...here and use new ISABSOLUTE macro. - -2004-04-04 Derek Price <derek@ximbiot.com> - - * client.c (send_file_names): Cast out an unneeded const to avoid a - warning. - -2004-04-03 Larry Jones <lawrence.jones@ugsplm.com> - - * client.c (send_file_names): Remove unused variables. - -2004-04-02 Derek Price <derek@ximbiot.com> - - * sanity.sh (client): Honor $keep. - -2004-04-02 Derek Price <derek@ximbiot.com> - - * log.c, patch.c, rcs.c: Gratuitous restyling. - -2004-04-02 Derek Price <derek@ximbiot.com> - - * import.c (import): Use ISDIRSEP rather than testing paths against `/' - directly. Some gratuitos reformatting. - -2004-04-02 Derek Price <derek@ximbiot.com> - - * sanity.sh: Note the effectiveness of `tail -f check.log' in providing - running status. - -2004-04-02 Derek Price <derek@ximbiot.com> - - * client.c (send_file_names): Move code which calculates and sends - Max-dotdot... - (send_max_dotdot): ...to this new function. - (send_files): Call send_max_dotdot. - * sanity.sh (files-14): Expect .. in paths to work now. - (status): Add a few new tests using `..'. - -2004-04-01 Derek Price <derek@ximbiot.com> - - * lock.c: Gratuitous restyling. - -2004-04-01 Derek Price <derek@ximbiot.com> - - * cvs.h, server.c: Gratuitous restyling. - * run.c (run_exec): Ditto, plus call cvs_flush{out,err}() instead of - flushing stderr & stdout directly. - -2004-03-29 Derek Price <derek@ximbiot.com> - - * server.c: Gratuitous restyling. - -2004-03-29 Derek Price <derek@ximbiot.com> - - * login.c: Gratuitous restyling. - -2004-03-22 Derek Price <derek@ximbiot.com> - - * sanity.sh (toplevel): Remove FIXME type comment and unneeded - Emtptydir removal. - -2004-03-22 Derek Price <derek@ximbiot.com> - - * update.c: Some minor style cleanup. - -2004-03-22 Derek Price <derek@ximbiot.com> - - * sanity.sh (top-level): Don't match most of the assertion since this - string is often system dependent. - (Thanks to Larry Jones <lawrence.jones@ugsplm.com>.) - -2004-03-22 Derek Price <derek@ximbiot.com> - - * sanity.sh (top-level): Don't match the assertion's line number. - -2004-03-22 Derek Price <derek@ximbiot.com> - - * sanity.sh (top-level): New test to confirm assertion failure. - -2004-03-22 Derek Price <derek@ximbiot.com> - - * sanity.sh: Only verify argument to -f when -f was passed. Check for - $TMPDIR/cvsXXXXXX temp files after each test. - -2004-03-22 Derek Price <derek@ximbiot.com> - - * sanity.sh: Verify that the argument to -f is really a test. - -2004-03-20 Larry Jones <lawrence.jones@ugsplm.com> - - * cvs.h: Change command_name to cvs_command_name to avoid conflict - on HP-UX (incredibly, it declares a global command_name in prot.h, - which is included from shadow.h, which we include in server.c). - Change all references. - - * subr.c (previous_rev): Fix == vs = typo. - - * buffer.h: Add prototype for buf_empty. - - * add.c (add): Remove unused variable. - -2004-03-20 Derek Price <derek@ximbiot.com> - - * add.c (add, add_directory, build_entry), admin.c (admin_dirproc), - checkin.c (Checkin), checkout.c (safe_location, build_dirs_and_chdir), - client.c (add_prune_candidate, send_repository, send_a_repository, - send_to_server, start_rsh_server, send_arg, send_modified, - send_ignproc, send_filesdone_proc, send_dirent_proc, - send_dirleave_proc, client_notify), commit.c (check_direntproc, - check_filesdoneproc, checkaddfile, commit_direntproc, - commit_dirleaveproc, lock_RCS, precommit_proc, find_data, - find_dirent_proc, find_ignproc, find_filesdoneproc), create_adm.c - (Create_Admin), cvsrc.c (read_cvsrc), diff.c (diff_dirproc, - diff_filesdoneproc, diff_dirleaveproc), edit.c (onoff_filesdoneproc, - mark_up_to_date, editor_set, notify_proc_args, notify_proc, notify_do, - notify_check), entries.c (Scratch_Entry, Register, WriteTag), - expand_path.c (expand_variable, expand_path), fileattr.c - (fileattr_startdir), filesubr.c (mkdir_if_needed, xchmod, - last_component), history.c (history_write), ignore.c (ignore_directory, - ignore_files), import.c (get_comment, add_rcs_file, expand_at_signs),xi - lock.c (lock_filesdoneproc), log.c (log_dirproc), logmsg.c - (logfile_write, rcsinfo_proc, update_logfile_proc, editinfo_proc, - verifymsg_proc, do_editor, do_verify, Update_Logfile), main.c (main - program_name, program_path, command_name), parseinfo.c (Parse_Info), - patch.c (patch_dirproc), rcs.c (RCS_getdatebranch, rcs_lockfilename, - RCS_parse, RCS_setattic, RCS_getversion, RCS_gettag, RCS_getbranch, - RCS_getdate, RCS_datecmp, RCS_getrevtime, RCS_setexpand, - expand_keywords, RCS_checkout, RCS_addbranch, RCS_checkin, RCS_lock, - RCS_cmp_file, RCS_deltas, rcs_lockfilename, make_file_label), - rcscmds.c (RCS_output_diff_options, call_diff, RCS_merge, - RCS_exec_rcsdiff, diff_exec), recurse.c (start_recursion, do_recursion, - do_file_proc), remove.c (remove_dirproc), repos.c (Name_Repository, - Short_Repository), root.c (Name_Root, Create_Root), run.c - (piped_child), server.c (output_dir, server_register, - server_checked_in, server_update_entries, server_copy_file, - server_set_entstat, server_clear_entstat, server_set_sticky, - server_template, cvs_output_tagged), status.c (status_dirproc), subr.c - (make_message_rcslegal), tag.c (pretag_proc, tag_dirproc, - check_fileproc, check_filesdoneproc, tag_fileproc, val_direntproc), - update.c (update_dirent_proc, update_dirleave_proc, update_ignproc, - update_filesdone_proc, isemptydir), vers_ts.c (time_stamp_server, - time_stamp), watch.c (watch_modify_watchers, addremove_filesdoneproc), - zlib.c (read_and_gzip): Make most string args const, mainly in the - interest of preserving repository & updatedir but including some - collateral damage. Update a few functions to comply with new - requirement. Some style fixes. - * client.h, cvs.h, edit.h, fileattr.h, rcs.h, server.h, update.h, - watch.h: Update prototypes to match. - -2004-03-20 Derek Price <derek@ximbiot.com> - - * sanity.sh (conflicts2): s/cvs/$testcvs/. - -2004-03-20 Derek Price <derek@ximbiot.com> - - * add.c (add): Correct longstanding resurrection bugs. Remove FIXME - comment to this effect. Set mode and Entries timestamps of resurrected - files correctly. - * sanity.sh (basica, binfiles, conflicts2, recase, resurrection, - update-p): Update tests to compensate. Remove FIXCVS comments. - -2004-03-19 Mark D. Baushke <mdb@cvshome.org> - - * server.c (gserver_authenticate_connection): Handle large - GSSAPI packets dynamically. - (Bug report from Douglas Engert <DEEngert@anl.gov>) - -2004-03-19 Derek Price <derek@ximbiot.com> - - * cvs.h (pathname_levels, previous_rev): Remove leading underscore from - prototype arguments to avoid potential conflicts with implementations. - -2004-03-18 Derek Price <derek@ximbiot.com> - - * cvs.h (pathname_levels): Make string argument const. - * subr.c (pathname_levels): Simplify function. - -2004-03-17 Derek Price <derek@ximbiot.com> - - * subr.c (pathname_levels): Get it right this time. - -2004-03-17 Derek Price <derek@ximbiot.com> - - * subr.c (pathname_levels): Remove incorrect assertion and just - return 0 when pathname is NULL. - -2004-03-17 Derek Price <derek@ximbiot.com> - - * subr.c (pathname_levels): Use ISDIRSEP() instead of strchr('/') - and remove FIXME comment to that effect. - -2004-03-16 Derek Price <derek@ximbiot.com> - - * main.c (main): Update the --version Copyright (c) string to - include 2004. - -2004-03-15 Mark D. Baushke <mdb@cvshome.org> - - * release.c (release): Add missing xmalloc of update_cmd. - -2004-03-15 Derek Price <derek@ximbiot.com> - - * release.c (release): Enable authentication and encryption for a child - update process when necessary. - (Original patch from Dan Russell <russelld@aol.net> via Hal Mahaffey - <HMahaffey@aol.com>.) - -2004-03-14 Derek Price <derek@ximbiot.com> - - * add.c (add): Only call server_updated() when we actual have a new - resurrected file for the client. - -2004-03-14 Derek Price <derek@ximbiot.com> - - * cvs.h (previous_rev, write_letter): New prototypes. - (struct file_info): Move to before the write_letter prototype. - * add.c (add): Allow resurrection of files which used to exist on a - branch. - * subr.c (previous_rev): New function. - * update.c: Consolidate like pragmas. - (write_letter): Remove prototype. Remove static declaration. - * sanity.sh (resurrection): New tests. - -2004-03-14 Derek Price <derek@ximbiot.com> - - * commit.c (remove_file): Print the actual previous revision instead of - a branch number. - * sanity.sh: Update to match. - -2004-03-14 Derek Price <derek@ximbiot.com> - - * rcs.c (RCS_cmp_file): Print the actual name of the file we failed to - open in the error message. - -2004-03-14 Derek Price <derek@ximbiot.com> - - * diff.c (diff_fileproc): Allow diffing of new files against arbitrary - revisions instead of assuming that there is no RCS archive file. - -2004-03-03 Derek Price <derek@ximbiot.com> - - * import.c (import): Check that the module name specified by the user - does not contain `CVS' as a directory name. - * ignore.c (ign_add): Never cease ignoring "CVS" - it is a reserved - name. - (Original patch from Dan Peterson <dbpete@aol.com>.) - - * sanity.sh (import-CVS): New tests for the above. - -2004-02-29 Larry Jones <lawrence.jones@ugsplm.com> - - * import.c (expand_at_signs): Change type of len to size_t. - * subr.c (resolve_symlink): Move declaration of newname inside - #ifdef, clean up coding style. - * zlib.c (gunzip_and_write): Fix up potential overlow problems. - (read_and_gzip): Add explicit casts to placate paranoid compilers. - -2004-02-28 Larry Jones <lawrence.jones@ugsplm.com> - - * sanity.sh (join6): New tests for previous fix. - - * update.c (join_file): One more fix to avoid dereferencing NULL. - (Reported by Steve McIntyre <steve@einval.com>.) - * sanity.sh (join6): New tests for above. - -2004-02-25 Larry Jones <lawrence.jones@ugsplm.com> - - * update.c (join_file): Fix optimization to avoid dereferencing NULL. - (Reported by Steve McIntyre <steve@einval.com>.) - -2004-02-25 Derek Price <derek@ximbiot.com> - - * buffer.c (buf_empty): New function. - * server.c (server): Check for unread data in buffer before closing. - -2004-02-25 Derek Price <derek@ximbiot.com> - - * release.c (release): Restore the initial directory before and after - calling various sections of code that expect it to prevent corruption - of CVS/Entries files on release of a subdir and tell unedit() what to - release. - * sanity.sh: Add test case for release.c fix. - (Original patch from Matthew Ogilvie <mmo9317bd@mailcan.com>.) - - * client.c (last_entries): Move global variable... - (call_in_directory): ...here (now a local variable). Remove test that - always evaluates to true. - (last_dir_name): Remove unused global variable. - -2004-02-24 Larry Jones <lawrence.jones@ugsplm.com> - - * filesubr.c (xresolvepath): Fix crash in error case. - (Reported by Reinhard Zierke <zierke@informatik.uni-hamburg.de>.) - -2004-02-24 Derek Price <derek@ximbiot.com> - - * sanity.sh (crerepos): Minor stylistic changes to previous change. - -2004-02-24 Derek Price <derek@ximbiot.com> - - * sanity.sh (crerepos): Fix it so that it ignores the user's - .cvsrc file (.cvsrc "checkout -r" used to cause the "rm -r 1" - command to print warnings and wait for input). - (Original patch from Matthew Ogilvie <mmo9317bd@mailcan.com>.) - - * sanity.sh (reposmv, parseroot, devcom3, binwrap3): - s/_SAVED\>/_save/ for consistency. - -2004-02-20 Derek Price <derek@ximbiot.com> - - * subr.c (set_nonblock_fd): Move back to... - * server.c: ...here. - * cvs.h: Remove protos for the above two functions. - * buffer.c (stdio_buffer_shutdown): Remove unexessary and possibly - dangerous check for unread data on a pipe with a nonblock read. - -2004-02-20 Derek Price <derek@ximbiot.com> - - * ChangeLog, commit.c, filesubr.c, rcs.c, root.c, sanity.sh, subr.c, - update.c: Remove VIM editor commands. - -2004-02-20 Larry Jones <lawrence.jones@ugsplm.com> - - * hash.h (struct node): Change data from char * to void *, change - all callers. - -2004-02-19 Larry Jones <lawrence.jones@ugsplm.com> - - * login.c (password_entry_operation): Initialize line. - -2004-02-19 Derek Price <derek@ximbiot.com> - - * sanity.sh (crerepos): Correct comment. - -2004-02-19 Derek Price <derek@ximbiot.com> - - * sanity.sh (crerepos): Don't create directories named `tmp' in - $TESTDIR to avoid conflicts with the default value of $TMPDIR. - -2004-02-19 Derek Price <derek@ximbiot.com> - - * sanity.sh (directory_cmp): Use $TESTDIR for temporary files, like the - dotest functions. - -2004-02-19 Derek Price <derek@ximbiot.com> - - * sanity.sh: No longer allow user override of $tmp. Set $TMPDIR to a - directory under $TESTDIR, as for $HOME, but still allowing for user - override. Check for cvs-serv* directories under $TMPDIR rather than - $tmp at the end of the script. - -2004-02-17 Derek Price <derek@ximbiot.com> - - * sanity.sh: Check for $PWD != $TESTDIR after each set of tests rather - than once at the end. Check that there are no cvs-serv* directories in - $tmp after each set of remote tests. - -2004-02-17 Derek Price <derek@ximbiot.com> - - * sanity.sh: Don't check for an empty $TESTDIR - if $TESTDIR was empty - then the preceding call to mkdir would have failed anyhow. - -2004-02-17 Larry Jones <lawrence.jones@ugsplm.com> - - * log.c (rlog_proc): Fix (harmless) uninitialized variable. - - * sanity.sh (basicc): Add tests pointing out defective handling - of the Entries file. - -2004-02-17 Derek Price <derek@ximbiot.com> - - * checkout.c (build_dir_and_chdir): Expand header comment. - -2004-02-15 Mark D. Baushke <mdb@cvshome.org> - - * annotate.c (rannotate_proc): Plug a memory leak. - * log.c (log_fileproc): Ditto. - * tag.c (tag_fileproc): Ditto. - * update.c (checkout_file): Ditto. - * server.c (server_updated): Do not buf_free (filebuf) here. - -2004-02-13 Larry Jones <lawrence.jones@ugsplm.com> - - * rcs.c (locate_rcs): Remove unused variables. - -2004-02-12 Mark D. Baushke <mdb@cvshome.org> - - * lock.c (readers_exist): Plug a memory leak. - -2004-02-12 Mark D. Baushke <mdb@cvshome.org> - - * server.c (do_cvs_command): Plug a memory leak. - -2004-02-12 Derek Price <derek@ximbiot.com> - - * modules.c: Reformat comment and line to fit in 80 chars. - -2004-02-12 Larry Jones <lawrence.jones@ugsplm.com> - - * modules.c (_do_module): Rename to my_module to avoid reserved name. - * stack.c (_push, _pop, _unshift, _shift): Rename to do_*. - -2004-02-11 Larry Jones <lawrence.jones@ugsplm.com> - - * root.c (parse_cvsroot): Set hostname in fork mode for error messages. - * buffer.c (stdio_buffer_shutdown): Undo previous change. - -2004-02-11 Mark D. Baushke <mdb@cvshome.org> - - * buffer.c (buf_free): Plug a memory leak. - * commit.c (checkaddfile): Ditto. - - * server.c (fd_buffer_shutdown): Avoid a double free(). - - * parseinfo.c (parse_config): Fix comments. - -2004-02-11 Derek Price <derek@ximbiot.com> - - * buffer.c (stdio_buffer_shutdown): Add logic to avoid attempting to - print current_parsed_root->hostname when using the fork method. - -2004-02-11 Derek Price <derek@ximbiot.com> - - * server.c (do_cvs_command): Simplify stream & pipe closing. - (Suggestion from Eric Siegerman <erics@telepres.com>.) - - * cvs.h, subr.c (set_block_fd): Remove this unnecessary function. - -2004-02-11 Derek Price <derek@ximbiot.com> - - * checkout.c (checkout_proc): s/is_absolute/isabsolute/. - -2004-02-11 Derek Price <derek@ximbiot.com> - - * checkout.c (checkout_proc): Remove unneeded variable and enclosing - block. - * modules.c (_do_modules): Minor whitespace change. - -2004-02-10 Derek Price <derek@ximbiot.com> - - * server.c (do_cvs_command): s/FIXCVS/FIXME/ in comment. - (set_block_fd, set_nonblock_fd): Move to... - * subr.c: ...here. - * cvs.h: Add protos for the above two functions. - * buffer.c (stdio_buffer_shutdown): Replace fgetc() which checked for - unread data on a pipe with a nonblock read. - -2004-02-10 Derek Price <derek@ximbiot.com> - - * server.c (do_cvs_command): Have the server child close all the pipes - but the flow control pipe and wait on an EOF on the flow control pipe - from the parent when done to avoid a race condition that could - otherwise generate a SIGPIPE for the parent before the SIGCHILD when - the other pipes were so full after a child exited that the parent - attempted to write a stop byte to the flow control pipe. - (Original report from <jesse_off@stchome.com>.) - -2004-02-10 Derek Price <derek@ximbiot.com> - - * buffer.c (stdio_buffer_shutdown): Add a helpful comment. - -2004-02-09 Derek Price <derek@ximbiot.com> - - * sanity.sh (co-d): Update comments and tests to reflect the current - state of my side of my discussion with Larry Jones on how these - commands should behave. - -2004-02-09 Derek Price <derek@ximbiot.com> - - * sanity.sh (emptydir): Add two new tests for how modules -d behaves - when a directory already exists in the user's workspace. - (emptydir): Add --keep functionality. - -2004-02-09 Derek Price <derek@ximbiot.com> - - * sanity.sh (co-d): New test to prove `co -d' failure case. - -2004-02-05 Derek Price <derek@ximbiot.com> - - * sanity.sh (recase): Fix typo that creeped in somehow between my last - test run and my commit. - -2004-02-04 Derek Price <derek@ximbiot.com> - - * stack.c (shift, shift_string): Make sure these functions return their - result. - -2004-02-04 Derek Price <derek@ximbiot.com> - - * modules.c (do_modules): Move content to and make this function a - wrapper for... - (_do_modules): ...this new function which can watch for infinite loops - in alias modules. - * stack.c (_push, _pop, _unshift, _shift, push_string, pop_string, - unshift_string, shift_string): New - functions. - * stack.h (push_string, pop_string, unshift_string, shift_string: New - prototypes. - * sanity.sh (modules): Add check for nested alias loops. - -2004-02-04 Derek Price <derek@ximbiot.com> - - * sanity.sh (recase): Update test names and comments for clarity and - consistency. - -2004-02-03 Derek Price <derek@ximbiot.com> - - Preserve the case of checked out directories in a path as well as file - names for client communication with the server. - - * Makefile.am (cvs_SOURCES): Add stack.c & stack.h. - * stack.c, stack.h: New files. - * cvs.h: Include stack.h. - * client.c (send_file_names): Preserve the case of directories in a - path as well as file names for communication with the server. - - * Makefile.in: Regenerated. - -2004-02-02 Derek Price <derek@ximbiot.com> - - * sanity.sh (join-rm): New test for issue #104 & #159. - -2004-02-02 Derek Price <derek@ximbiot.com> - - Continue removal from server of handling of case insensitive clients. - - * cvs.h: Remove extern declaration of ign_case. - * ignore.c (ign_case): Remove declaration. - (ign_name): Remove support for ign_case. - * server.c (serve_case): Ditto. - (requests): No longer support the "Case" request. - * rcs.c (locate_rcs): Remove reference to GLOBAL in function header - comment. - -2004-02-02 Derek Price <derek@ximbiot.com> - - * add.c, client.c, cvs.h, rcs.c, subr.c: Remove server support for case - insensitivity. - -2004-01-25 Derek Price <derek@ximbiot.com> - - * server.c (kserver_authenticate_connection): Fix call to - switch_to_user(). - (Original patch from Alexey Mahotkin <alexm@hsys.msk.ru>.) - -2004-01-22 Derek Price <derek@ximbiot.com> - - * modules.c (do_module): Strip trailing slashes before checking for - infinite alias loops. - * sanity.sh (modules): Tests for response to infinite alias loops. - -2004-01-17 Mark D. Baushke <mdb@cvshome.org> - - * logmsg.c (do_verify): Eliminate double-free bug. - (Original patch from Gerald Combs.) - -2004-01-07 Larry Jones <lawrence.jones@ugsplm.com> - - * checkout.c (safe_location): Remove unused variable(s). - * lock.c (lock_tree_for_write): Ditto. - * rcs.c (RCS_checkin): Ditto. - * subr.c (compare_revnums): Ditto. - * tag.c (tag_check_valid): Ditto. - * mkmodules.c (init): Initialize err and return it rather than 0. - * server.c (do_cvs_command): Only define and set max_command_fd if - we're actually going to use it. - -2004-01-01 Larry Jones <lawrence.jones@ugsplm.com> - - * zlib.c (read_and_gzip, gunzip_and_write): Fix potential buffer - overruns, use names for magic numbers. - (Original patch from Jeff Downs <heydowns@borg.com>.) - -2003-12-18 Derek Price <derek@ximbiot.com> - - * server.c (switch_to_user): SysLog attempts to root from pserver. - -2003-12-18 Derek Price <derek@ximbiot.com> - - * server.c (switch_to_user): Don't allow CVS to run as root in pserver - mode. - (Original patch from Wichert Akkerman via Bradley M Kuhn - <bkuhn@fsf.org>.) - * sanity.sh (pserver): Check for bad root error message. - -2003-12-17 Larry Jones <lawrence.jones@eds.com> - - * run.c (close_on_exec): fcntl is not documented to return 0 for - success (and QNX doesn't), only -1 for error. - (Patch from George Refseth <george.refseth@arxi.no>.) - -2003-12-09 Mark D. Baushke <mdb@cvshome.org> - - * server.c (template_proc): Fix broken Template protocol code. - Must call send buf_send_counted() for Template files to avoid - "Protocol error: uncounted data discarded" messages in some - circumstances. - (Problem reported by "Jim.Hyslop" <Jim.Hyslop@Leitch.com>.) - -2003-12-03 Derek Price <derek@ximbiot.com> - - * sanity.sh (recase-8csss): rename to... - (recase-8sscs): ...this to match the convention. - -2003-12-03 Derek Price <derek@ximbiot.com> - - * sanity.sh (recase): Add some clarifying comments. - -2003-12-03 Larry Jones <lawrence.jones@eds.com> - - * expand_path.c (expand_variable): Expand ${CVSROOT} to just the - directory like it's supposed to be. - (Reported by Michael S. Tsirkin <cvs1@misha.eml.cc>.) - -2003-11-26 Derek Price <derek@ximbiot.com> - - * sanity.sh (modules3-2): Simplify syntax that may have given Cygwin - intermittent conniptions. - -2003-11-25 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (recase-17sscs): Use ${CVSROOT_DIRNAME} in pattern. - -2003-11-25 Derek Price <derek@ximbiot.com> - - * sanity.sh (release): Perform forgotten cleanup. - -2003-11-25 Derek Price <derek@ximbiot.com> - - * commit.c (commit_fileproc): Reword comment. - -2003-11-25 Derek Price <derek@ximbiot.com> - - * add.c (add): Disable ign_case for the purposes of adding a file so - that recasing the name of a file is possible from a case insensitive - client. - * sanity.sh (recase): New tests for behavior which varies when the - client and/or the server are case insensitive. - -2003-11-25 Derek Price <derek@ximbiot.com> - - * sanity.sh (devcom3-9ar): Ignore the stderr output since it varies - considerably between platforms. - -2003-11-24 Larry Jones <lawrence.jones@eds.com> - - * diff.c (diff_file_nodiff): use_rev1 does *not* imply that diff_rev1 - is not null, diff_date1 could be set instead (ditto for use_rev2). - (Reported by <jnelson-cvsbug@jamponi.net>.) - -2003-11-24 Derek Price <derek@ximbiot.com> - - * sanity.sh (modes3): Skip modes3-5 entirely under Cygwin since - permisions are broken there. This change removes most of the earlier - Cygwin differentiation in this test ($cygwin_hack & $cygwin_hack2) in - favor of skipping the test entirely. - -2003-11-21 Larry Jones <lawrence.jones@eds.com> - - * hash.c (printnode, printlist): Cast %p arguments to void * as - required by the C standard. - -2003-11-21 Derek Price <derek@ximbiot.com> - - * sanity.sh: Add `-h <hostname>' option to enable testing across a - :ext: connection to another host. Warn when `-h' is specified without - $TESTDIR. Leave $TESTDIR intact when it looks absolute since it may - contain symlinks. Allow $CVS_SERVER to be overridden via the - environment for `-h'. Default $CVS_RSH to `rsh'. - (*): Use $CVS_RSH to perform certain commands on the remote host (esp. - `ln -s' and `chmod') when `-h' is specified to work around - incompatibilities with CygWin & Samba. Add a few other minor - workarounds for Cygwin bugs. - - (newroot): New function. - (*): Use newroot when appropriate. - -2003-11-19 Larry Jones <lawrence.jones@eds.com> - - * rcs.c (RCS_getrevtime): Add error checking; cleanup. - -2003-11-18 Derek Price <derek@ximbiot.com> - - * modules.c (do_module): Reject absolute paths. - (Report and suggested fix from Tony Hoyle <tmh@nodomain.org>.) - - * sanity.sh (abspath2): Check for the above. - (spacefiles): Remove tests that expect absolute paths to files in the - top level repository directory to work. - (tests): Add abspath2. - -2003-11-13 Derek Price <derek@ximbiot.com> - - * rcs.c (RCS_delete_revs): It's `&&', not `and'. - -2003-11-13 Derek Price <derek@ximbiot.com> - - * sanity.sh: Create the empty log to make it easier to tail immediately - after the script is started. - -2003-11-13 Derek Price <derek@ximbiot.com> - - * sanity.sh (exit_help): Correct help to specify `-H' and not `-h' as - the help option. - -2003-11-13 Derek Price <derek@ximbiot.com> - - * rcs.c (RCS_delete_revs): Don't use the WOE32 kludge which refuses to - delete revisions from bvinary files on Cygwin. I'm not sure what the - kludge was trying to avoid, but commenting it out causes the test suite - to pass. - -2003-11-10 Derek Price <derek@ximbiot.com> - - * commit.c (check_fileproc, find_fileproc): Don't leak memory. - -2003-11-10 Derek Price <derek@ximbiot.com> - - * commit.c (find_fileproc, check_fileproc): Refuse to remove files - when the file exists in the sandbox. This used to cause data loss. - (Report from Andreas Reifschneider <andyreif@studcs.uni-sb.de>.) - - * sanity.sh (rmadd3): Update to match. Expand comments. - -2003-11-10 Derek Price <derek@ximbiot.com> - - * sanity.sh (rmadd3): Test the behavior of commit after the - add/replace. - (Report from Andreas Reifschneider <andyreif@studcs.uni-sb.de>.) - -2003-11-10 Mark D. Baushke <mdb@cvshome.org> - - * Backport symlink bugfix from cvs 1.12.1.1 feature release - as written by Derek Price <derek@ximbiot.com>. (This fixes - the Issue 142 bug.) - - * recurse.c (start_recursion): Accept new repository argument so - that the working directory may be tracked by do_recursion without - using xgetwd(), which returned a value different from the one the - user requested when symlinks were in use. Pass repository_in to - do_recursion() as part of the recursion frame. - - * cvs.h (xreadlink): #ifdef HAVE_READLINK proto. - (xresolvepath): New proto. - (start_recursion): Add repository to proto. - - * checkout.c (safe_location): Add more complete header comment. - Add trace. Use new xresolvepath() function. Always return true - in client mode since checking our destination path against the - CVSROOT path is usually meaningless in client/server mode. - (checkout_proc): Pass repository to do_update() for later use with - start_recursion(). - - * admin.c (admin): Use new definition of start_recursion(). - * annotate.c (rannotate_proc): Ditto. - * client.c (send_files): Ditto. - * commit.c (commit): Ditto. - * diff.c (diff): Ditto. - * edit.c (watch_onoff, send_notifications, edit, unedit, editors): - Ditto. - * lock.c (lock_tree_for_write): Ditto. - * log.c (rlog_proc): Ditto. - * patch.c (patch_proc): Ditto. - * remove.c (cvsremove): Ditto. - * tag.c (rtag_proc): Ditto. - * update.c (do_update): Ditto. - * watch.c (watch_addremove, watchers): Ditto. - - * patch.c (patch_proc): Call tag_check_valid with repository - instead of NULL. - - * filesubr.c (xreadlink): #ifdef HAVE_READLINK this function. Add - more complete header comment. - (xresolvepath): New function. - - * recurse.c (do_recursion): Call Lock_Cleanup() only repository - was set. - - * update.c (do_update): Accept new repository argument so that the - working directory may be tracked. - (update): Pass NULL repository to do_update(). - * update.c (do_update): Add repository to proto. - - * checkout.c (checkout_proc): Use new definition of do_update(). - * update.c (update): Ditto. - - * sanity.sh: Add new -l option to test symlinked roots. - (checkout_repository-1): Add server error messages about absolute - paths since the client now skips destination validity checks. - (check_repository-2): Test renamed to checkout_repository-2. - (checkout_repository-2): Process client error messages about - CVSROOT files being in the way since the client skips destination - validity checks since it should be rare that a client is running - in client/server mode on the server and CVS has no current way to - check if it is running on the server. - (check_repository-3): Test renamed to checkout_repository-3. - (dottedroot): New test to check that a CVSROOT with a "." in the - name will work. - -2003-11-10 Derek Price <derek@ximbiot.com> - - * sanity.sh (rmadd3): Add whitespace after end of test for readability. - -2003-11-10 Derek Price <derek@ximbiot.com> - - * sanity.sh (rmadd3): New tests that confirms that CVS refuses to - delete a file it thinks was already removed. - (Report and test from Andreas Reifschneider - <andyreif@studcs.uni-sb.de>.) - -2003-11-03 Derek Price <derek@ximbiot.com> - - * sanity.sh (server): Test that the global `-l' option is ignored - nonfatally. - -2003-11-01 Larry Jones <lawrence.jones@eds.com> - - * ignore.c (ignore_files): Use CVS_LSTAT() instead of lstat(). - * filesubr.c (xcmp): Make sure S_ISLNK exists before calling it. - (Reported by Paul Edwards <fight.subjugation@gmail.com>.) - -2003-10-31 Derek Price <derek@ximbiot.com> - - * sanity.sh (checkout_repository): Name tests consistently. - -2003-10-31 Derek Price <derek@ximbiot.com> - - * sanity.sh: s/${TESTDIR}/cvsroot/${CVSROOT_DIRNAME}/. - -2003-10-28 Derek Price <derek@ximbiot.com> - - * sanity.sh (devcom): s/cvs/$PROG/. - -2003-10-28 Derek Price <derek@ximbiot.com> - - * sanity.sh (devcom): Renumber tests and use dotest function. - -2003-10-28 Derek Price <derek@ximbiot.com> - - * sever.h: Add the standard copyright notice. - -2003-10-28 Derek Price <derek@ximbiot.com> - - * lock.c: Remove some suggestions which have already been implemented - or which have become obsolete from the header comment. - -2003-10-26 Derek Price <derek@ximbiot.com> - - * sanity.sh (join6): Fix a few typos in the last test and remove a - misplaced test. - -2003-10-25 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (parseroot): Perform this test in a subdirectory. - It should avoid problems on case-insensitive systems where - CVSROOT and cvsroot are the same directory (eg, MacOS X). - -2003-10-24 Derek Price <derek@ximbiot.com> - - * update.c (join_file): Restore the optimization Mark recently removed, - but fix it. Move one other optimization up since it needs to be - checked for first. Add bew status messages like merge_file produces - when the requested diff has already been applied to the destination. - Expand header comment. - * sanity.sh (join6): Add tests for the new error messages. - (import-113, join-admin-2, diffmerge1): Fix collateral damage. - -2003-10-23 Mark D. Baushke <mdb@cvshome.org> - - * update.c (join_file): Do the -jrev1 -jrev2 merge even when - the file is already at rev2. - * sanity.sh (join6): New testcase for above. - (Suggested by Paul Edwards, from somewhere in Australia.) - (import): Fix collateral damage. - -2003-10-23 Derek Price <derek@ximbiot.com> - - * sanity.sh (fail): Refer the user to the `TESTS' and `check.log' files - on failure. - -2003-10-19 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (admin-31): Fix more typos. - -2003-10-18 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (admin): Fix a typo. - - * admin.c (admin_fileproc): Restore the ':' character in the - -mtag:message admin argument even if the tag does not exist so - that other files with the tag will be found. Also, be more - paranoid that a symbolic tag actually points to a version that - exists. - (Reported by Rodolfo Schulz de Lima <rodolfo@rodsoft.org>.) - * sanity.sh (admin): Test these changes. - -2003-10-17 Mark D. Baushke <mdb@cvshome.org> - - * admin.c (admin_fileproc): Force tag match on admin - -mversion:message rather than altering the wrong log message. - (Patch from "Rodolfo Schulz de Lima" <rodsoft@uol.com.br>.) - * sanity.sh (admin): Test case for it. - -2003-10-15 Larry Jones <lawrence.jones@eds.com> - - * commit.c (commit_fileproc, finaladd): Don't call fixaddfile() - if the RCS file didn't get created at all. - (Reported by David Wood <David.Wood@thestreet.com>.) - -2003-10-14 Derek Price <derek@ximbiot.com> - - Port to pedantic POSIX 1003.1-2001 hosts, such as Debian GNU/Linux - testing with _POSIX2_VERSION=200112 in the environment. - - * sanity.sh: Use 'sed 1q', not 'head -1'. - (Patch from Paul Eggert <eggert@twinsun.com>.) - -2003-10-10 Derek Price <derek@ximbiot.com> - - * lock.c (set_lock): Clarify comment. - -2003-10-08 Derek Price <derek@ximbiot.com> - - * Makefile.am (cvs_SOURCES): Add history.h. - * history.c: Include history.h. Add the `P' record types to more - comments. s/ALL_REC_TYPES/ALL_HISTORY_REC_TYPES/. - (usage): Reference ALL_HISTORY_REC_TYPES rather than using a separate - string literal. - (report_hrecs): Handle `P' record type. - (ALL_REC_TYPES): Rename and move... - * history.h (ALL_HISTORY_REC_TYPES): ...here. - * mkmodules.c: Include history.h. - (config_contents): Update contents of and references to LogHistory - records to use ALL_HISTORY_REC_TYPES. - * sanity.sh (basic2-64): Update to include history records of type `P'. - - * Makefile.in: Regenerated. - -2003-10-08 Derek Price <derek@ximbiot.com> - - * update.c (patch_file): Correct spelling and punctuation in comment. - Update some lines to fit in 80 characters. - -2003-10-08 Larry Jones <lawrence.jones@eds.com> - - * history.c (history): Don't conflate -e with -x since the client's - idea of what -e means may not match the server's. - (Reported by Frank Hemer <frank@hemer.org>.) - -2003-10-07 Larry Jones <lawrence.jones@eds.com> - - * sanity.sh: Use dotest_fail instead of dotest_status for diff tests - since CVS only returns success/fail rather than 0/1/2 like diff does. - -2003-10-07 Derek Price <derek@ximbiot.com> - - Fix a client/server bug introduced via the data loss fix of 2003-03-17. - Basically, the server was reporting ambiguous filename requests when it - should have been trusting the user to type the intended case or using - the case the client preserved in CVS/Entries before it tried to look - anything up in case insensitive mode. - - * rcs.c (locate_rcs): Use the filename exactly as cased before - investigating a case insensitive lookup, per the client/server protocol - specification. Expand comments. - * subr.c (locate_file_in_dir): This function only needs to locate files - case insensitively. Expand comments. - * cvs.h (locate_file_in_dir): Only prototype when servers which need to - handle case insensitivity are being compiled. - -2003-10-07 Derek Price <derek@ximbiot.com> - - * rcs.c (locate_rcs): Declare static. Move to an earlier location in - file to avoid prototyping. - * rcs.h (locate_rcs): Remove proto. - -2003-10-03 Derek Price <derek@ximbiot.com> - - * server.c (serve_global_option): Warn that -l is being ignored rather - than exiting fatally due to backwards compatibility complaints from - administrators. - -2003-09-29 Derek Price <derek@ximbiot.com> - - * rcs.c (make_file_label): Make a failure to stat a file a fatal error - since it signals that a later read will also fail. - -2003-09-26 Derek Price <derek@ximbiot.com> - - * diff.c (diff): Add a FIXME re spaces in diff arguments. - -2003-09-25 Mark D. Baushke <mdb@cvshome.org> - - * rcs.c (make_file_label): Do not return an uninitialized label. - (Reported by "Todd C. Miller" <Todd.Miller@courtesan.com>) - -2003-09-12 Derek Price <derek@ximbiot.com> - - * sanity.sh (mkmodules): Correct comments. - -2003-09-12 Derek Price <derek@ximbiot.com> - - * mkmodules.c (mkmodules): Do not pass a string which came from the - checkoutlist file directly to error as a format string since we don't - want to trust any user with access to checkoutlist with creating printf - format strings. I already claimed I did this in the NEWS file. - (Thanks to Larry Jones for spotting my mistake.) - * sanity.sh (mkmodules): Test for the above. - -2003-09-12 Derek Price <derek@ximbiot.com> - - * mkmodules.c (checkoutlist_contents): Document the optional portions - of this file format more accurately. - (mkmodules): Ditto, in comments. Fix bug that always failed to ignore - whitespace before error messages. - * sanity.sh (mkmodules-temp-file-removal): Rename to... - (mkmodules): ...this and add a test of the checkoutlist error message. - Add cleanup step to restore checkoutlist. - -2003-08-27 Larry Jones <lawrence.jones@eds.com> - - * history.c: 'P' is a valid record type and has been for a long time. - Add it to the comments, usage message, and, most important, - ALL_REC_TYPES so it gets recorded by default. - * server.c (do_cvs_command): Set global command_name to the real - command name rather than leaving it set to "server". - * sanity.sh: Update to match. - (Reported by Dmitry Ryzhkov <rdim_outside@softhome.net>.) - -2003-08-13 Larry Jones <lawrence.jones@eds.com> - - * server.c (server_cleanup): Don't shutdown buf_from_net if it's - null. - (Reported by Scott Mitchell <scott@fishballoon.org>.) - -2003-08-01 Derek Price <derek@ximbiot.com> - - * sanity.sh (join5): Use $PROG consistently and escape a `.'. - -2003-08-01 Derek Price <derek@ximbiot.com> - - * sanity.sh (join5): Use `[a-z]*' as opposed to `update'. - -2003-07-31 Derek Price <derek@ximbiot.com> - - * add.c (add_directory): Restore a malloc I shouldn't have altered on - the stable branch. - -2003-07-31 Derek Price <derek@ximbiot.com> - - * rcscmds.c (RCS_merge): Pass `--' before the filename arguments to - diff so that filenames starting with `-' can be merged. - * sanity.sh (join5): New test for same. - -2003-07-31 Derek Price <derek@ximbiot.com> - - * add.c (add_directory): Don't print status information in really_quiet - mode. - -2003-07-29 Derek Price <derek@ximbiot.com> - - * commit.c (checkaddfile): Simplify the logic here, using assumptions - already made later in the function to remove calls to locate_rcs and - some conditionals. Use same assumptions to remove some variables. - -2003-07-29 Derek Price <derek@ximbiot.com> - - * login.c: Remove GETPASS & HAVE_GETPASSPHRASE cruft in favor of always - using the GNULIB getpass since the system getpass was removed from the - POSIX.2 specification. - -2003-07-28 Derek Price <derek@ximbiot.com> - - * subr.c (strip_trailiing_newlines): Use size_t rather than int to - count string length. - (Suggestion from Paul Edwards, who provides a broken return email - address in Tonga. I believe he is actually from Australia.) - -2003-07-28 Derek Price <derek@ximbiot.com> - - * checkout.c (checkout): Remove out-of-date comment about Checkin.prog - and Update.prog. - -2003-07-25 Derek Price <derek@ximbiot.com> - - * rcs.c (RCS_parsercsfile): Declare rcsfile argument as const. - * rcs.h (RCS_parsercsfile): Update prototype to match. - * commit.c (fixaddfile): Accept a single path to an rcs file as an - argument rather than trying to look it up again when it is not - necessary. - -2003-07-25 Derek Price <derek@ximbiot.com> - - * commit.c (finaladd): But don't free variables we no longer allocate. - -2003-07-25 Derek Price <derek@ximbiot.com> - - * checkin.c (Checkin): The rcs argument is unecessary since we know - that the parsed RCS data always exists as part of finfo by the time - this function gets called. - * commit.c (commit_fileproc, finaladd): Use new Checkin() API. - * cvs.h (Checkin): Update prototype. - -2003-07-25 Derek Price <derek@ximbiot.com> - - * subr.c (strip_trailing_newlines): Check len b4 str[len] to avoid - exceeding the array bounds when the string length == 0. - (Report from John Tytgat <JoTy@esko-graphics.com>.) - -2003-07-25 Derek Price <derek@ximbiot.com> - - * subr.c (strip_trailing_newlines): Generalize this function to watch - len so that it cannot walk past the beginning of the string passed in. - (Report from John Tytgat <JoTy@esko-graphics.com>.) - -2003-07-25 Derek Price <derek@ximbiot.com> - - * subr.c (strip_trailing_newlines): Leave the K&R function decl on this - branch. - -2003-07-25 Derek Price <derek@ximbiot.com> - - * cvs.h (strip_trailing_newlines): Update prototype. - * subr.c (strip_trailing_newlines): Return true when newlines are - removed. - * server.c (pserver_authenticate_connection): Don't give a DOS attack a - chance to authenticate accidentally because I like to be paranoid. - * sanity.sh (pserver): New test for same. - -2003-07-20 Derek Price <derek@ximbiot.com> - - * wrapper.c: Remove mention of obsolete -f and -t wrapper options from - a comment. - -2003-07-12 Larry Jones <lawrence.jones@eds.com> - - * sanity.sh (diffnl): New tests for diff on files with no newline - at end. - (Patch from Andrew Moise <chops@demiurgestudios.com>.) - -2003-07-09 Larry Jones <lawrence.jones@eds.com> - - * add.c (add): Update "re-adding" message to have quotes around - the file name like all the other similar messages. - * sanity.sh: Update to match. - - * update.c (join_file): Handle locally removed but not yet committed - files. - (Reported by Larry Lords <LordsLL@ldschurch.org>.) - * sanity.sh (join, join4): New tests for above. - -2003-06-28 Larry Jones <lawrence.jones@eds.com> - - * commit.c (fixaddfile): Bail out if locate_rcs() fails. Make - parameters const. - - * add.c (add): Fix -Wall complaints. - * diff.c (diff_file_nodiff): Ditto. - * filesubr.c (cvs_casecmp): Ditto. - * patch.c (patch_fileproc): Ditto. - * rcs.c (RCS_cmp_file): Ditto. - * root.c (parse_cvsroot): Ditto. - * subr.c (locate_file_in_dir): Ditto. - * cvs.h (cvs_casecmp, locate_file_in_dir): Update prototypes. - -2003-06-27 Larry Jones <lawrence.jones@eds.com> - - * lock.c (readers_exist): Use LockDir rather than always looking - in the repository. - (Original patch from Robert Ambalu <Robert.Ambalu@gs.com>.) - Remove vestigial lock promotion code. - -2003-06-26 Larry Jones <lawrence.jones@eds.com> - - * hash.c (sortlist): Avoid crash when list is null. - -2003-06-23 Derek Price <derek@ximbiot.com> - - * patch.c (patch_fileproc): Output revision number of the original - revision in the removed case. - (Idea from Paul Edwards <kerravon@w3.to>.) - - * sanity.sh (rdiff-add-remove-nodiff): Rename to... - (rdiff-short): ...this. Test for the above changes. Add some tests - for when rev2 defaults to the trunk. Expand comments. - -2003-06-23 Derek Price <derek@ximbiot.com> - - * add.c (add): Fix xmalloc's strlen() of wrong variable. - * checkout.c (safe_location): leak: reused where_location without free. - * log.c (rlog_proc): leak: free where before exit. - * logmsg.c (do_verify): leak: free verifymsg_script before exit. - (Original patch from Kenneth Lorber <keni@his.com>.) - -2003-06-20 Derek Price <derek@ximbiot.com> - - * client.c: Remove silly comment. - (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.) - -2003-06-13 Derek Price <derek@ximbiot.com> - - * subr.c (file_has_conflict): Fix comment. - (Patch from Paul Edwards <kerravon@w3.to>.) - -2003-06-13 Derek Price <derek@ximbiot.com> - - * subr.c (xrealloc): Trivial comment fix. - (Patch from Kenneth Lorber <keni@his.com>.) - -2003-06-13 Derek Price <derek@ximbiot.com> - - * diff.c (diff_fileproc): Fix memory leak. - (Patch from Kenneth Lorber <keni@his.com>.) - -2003-06-12 Derek Price <derek@ximbiot.com> - - * root.c (parse_cvsroot, local_cvsroot): Parse trailing '/'s off the - end of cvsroots. Make arguments const. - * cvs.h: Update prototypes to match. - (Idea from Miles Zarathustra <shiva@aranyaka.org>.) - -2003-06-11 Larry Jones <lawrence.jones@eds.com> - - * sanity.sh: Change warning messages to note that defective tools - can result in defective results, both pass and fail. Also change - "which" to "that" for errant grammar pedants. - -2003-06-09 Derek Price <derek@ximbiot.com> - - * rcs.c (RCS_delete_revs): Reference WOE32 rather than WIN32 in - accordance with the GNU convention to avoid implying that we consider - the Microsoft Windows Operating Environment any sort of "win". - -2003-06-09 Derek Price <derek@ximbiot.com> - - * filesubr.c (cvs_temp_file): Tidy a comment. - -2003-06-09 Derek Price <derek@ximbiot.com> - - * patch.c (patch_fileproc): Don't assume the content of files is - different just because the revision number is different. - * sanity.sh (rdiff-add-remove-nodiff): New tests for the above. - (Report & original patches from Paul Edwards <kerravon@w3.to>.) - -2003-06-04 Derek Price <derek@ximbiot.com> - - * cvs.h (locate_file_in_dir): New proto. - (locate_rcs): Move proto... - * rcs.h: ...here. - * filesubr.c (locate_rcs): Move function... - * rcs.c: ...here for Windows. - * filesubr.c (locate_file_in_dir): Move function... - * subr.c: ...here for Windows. - -2003-06-02 Derek Price <derek@ximbiot.com> - - * diff.c (diff_file_nodiff): Don't assume that because two specified - revision numbers are different, the contents are different. - (Original report & patch from Paul Edwards <kerravon@w3.to>.) - - * diff.c (diff_file_nodiff): Pass through rev1_cache to be filled in - by RCS_cmp_file when it needs to check out revision 1 into a file. Add - some more informative error messages. Cleanup for efficiency & - readability. - (diff_fileproc): Pass the cached revision to RCS_exec_diff(). Clean up - the error exit code. Remove code killed by the changes to - diff_file_nodiff(). - * rcscmds.c (RCS_exec_rcsdiff): Accept and use new cached revision text - if present. - * rcs.c (RCS_cmp_file): Accept a second revision number and cache the - first revision if it needs to be checked out. - - * checkin.c (Checkin): Use new RCS_cmp_file(). - * import.c (update_rcs_file): Ditto. - * no_diff.c (No_Difference): Ditto. - - * cvs.h (RCS_exec_rcsdiff): New proto to match above changes. - * rcs.h (RCS_cmp_file): Ditto. - - * sanity.sh: Minor corrections to handle the above changes. - -2003-05-29 Derek Price <derek@ximbiot.com> - - * client.c (start_server): Don't send -l to server. - * history.c (history_write): Fix comment. - * main.c (main): Don't process -l. - * server.c (serve_global_option): Ditto. - (Suggestion from Rob Lanphier <robla@real.com>.) - -2003-05-23 Larry Jones <lawrence.jones@eds.com> - - * sanity.sh (info-cleanup-verifymsg): Avoid race in output. - -2003-05-22 Larry Jones <lawrence.jones@eds.com> - - * commit.c (commit): Fix leading zero stripping code to not strip - unless there's a following digit. - - * parseinfo.c (Parse_Info): Warn if multiple DEFAULT lines found. - * sanity.sh (info): New test for above. - -2003-05-21 Derek Price <derek@ximbiot.com> - - * Makefile.in: Regenerate with Automake version 1.7.5. - -2003-05-20 Larry Jones <lawrence.jones@eds.com> - - * parseinfo.c (Parse_Info): Fix stupid memory management error. - - * logmsg.c (do_verify): Treate Parse_Info errors as failure. - * parseinfo.c (Parse_Info): Don't call expand_path until executing - the command so that errors in unexecuted commands aren't reported. - * sanity.sh (info): New tests for above. - -2003-05-18 Mark D. Baushke <mdb@gnu.org> - - * Makefile.am (localcheck,remotecheck): Use cvs$(EXEEXT) not cvs. - * Makefile.in: Regenerated. - * sanity.sh (status-init-7): Use ${PROG} not cvs in tests. - (branch-after-import-5): Ditto. - (keywordname-update-11): Ditto. - -2003-05-18 Larry Jones <lawrence.jones@eds.com> - - * server.h (kserver_authenticate_connection, - pserver_authenticate_connection): Add prototypes. - - * client.c (update_entries): Set file's access time to the current - time rather than the same as the modification time. - * vers_ts.c (Version_TS): Ditto. - -2003-05-01 Derek Price <derek@ximbiot.com> - - * main.c (main): Ignore -z when CLIENT_SUPPORT is not defined. - (Report from Jim Salter <jsalterjim@earthlink.net>.) - -2003-05-01 Derek Price <derek@ximbiot.com> - - * repos.c (Sanitize_Repository_Name): Remove some old comments about - the defunct RELATIVE_REPOS macro. - * server.c (outside_root): Ditto. - -2003-04-30 Derek Price <derek@ximbiot.com> - - * add.c (add): Fix a possible, if unlikely, memory out of bounds error. - -2003-04-28 Derek Price <derek@ximbiot.com> - - * client.c (save_prog): Remove unneeded struct. - (checkin_progs, update_progs): Remove these unneeded globals. - (handle_set_checkin_prog, handle_set_update_prog, do_deferred_progs): - Remove these functions. - (send_repository): Remove checkin and update prog support. - (responses): Remove Set-checkin-prog and Set-update-prog. - (get_responses_and_close): Don't call do_deferred_prog(). - * commit.c (commit_usage): Remove reference to -n. - (commit): Don't set and send run_module_prog via -n. Don't run - Checkin.prog or Checkout.prog in local mode. - * modules.c (CVSMODULE_OPTS): Remove -i and -u. - (do_module): Don't process -i and -u options to set checkin and update - progs, respectively. - * server.c (server_prog, serve_checkin_prog, server_update_prog): - Remove unused functions. - (requests): Remove Checkin-prog and Update-prog. - * update.c (update_dirleave_proc): Remove update prog functionality. - - * cvs.h (CVSADM_CIPROG, CVSADM_UPROG): Remove unneeded defines. - * server.h (server_prog): Remove proto. - (progs): Remove enum. - - * sanity.sh (modules5): Remove tests for checkin and update programs. - -2003-04-10 Larry Jones <lawrence.jones@eds.com> - - * Makefile.in: Regenerated. - -2003-03-27 Mark D. Baushke <mdb@cvshome.org> - - * sanity.sh (rdiff2): Add new test case for SEGV problem reported - against cvs 1.11.5. - (Report from James Cribb) - -2003-03-26 Derek Price <derek@ximbiot.com> - - * client.c: Fix, reorganize, and comment ifdefs for AUTH_CLIENT_SUPPORT - and HAVE_GSSAPI. - * client.h: Ditto. Remove some unecessary server function prototypes. - -2003-03-26 Derek Price <derek@ximbiot.com> - - * client.c: Include the net headers for HAVE_GSSAPI. - (Report from Jim Salter <jsalterjim@earthlink.net>.) - -2003-03-26 Derek Price <derek@ximbiot.com> - - * main.c (main): Verify the argument to -z when running without - CLIENT_SUPPORT since Eric Siegerman complained about being bit - by a run of `cvs -z -n up' which parsed the -n as the argument to - -z. - * sanity.sh (opterrmsg): New tests for -z argument checking. - -2003-03-26 Larry Jones <lawrence.jones@eds.com> - - * main.c (main): Use strtol() instead of atoi() when parsing -z - to detect errors. - (Reported by Eric Siegerman <erics@telepres.com>.) - -2003-03-24 Derek Price <derek@ximbiot.com> - - * Makefile.am: Update copyright notice. - - * Makefile.in: Regenerated. - -2003-03-19 Larry Jones <lawrence.jones@eds.com> - - * filesubr.c (mkdir_if_needed): Save errno since isdir() can clobber. - (Patch from Brian Poole <raj@cerias.purdue.edu>.) - * sanity.sh (abspath-4): Update to match. - - * filesubr.c (locate_rcs): Fix gcc warning. - -2003-03-17 Derek Price <derek@ximbiot.com> - - * add.c: Correct comment. - * client.c: Ditto. - * checkin.c (Checkin): Pass work file name to RCS_checkin so that this - function works properly in the case insensitive mode. - * commit.c (checkaddfile): Fix and factor add logic so that the - correct files and directories are created in the case insensitive mode. - Reuse code in RCS_parse() below. This avoids a problem that could - cause corrupted RCS files to be created on an add from a case - insensitive system. Corrupted RCS files could cause later assertion - failures for everyone. - (locate_rcs): Move this function... - * filesubr.c (locate_rcs): ...here and rewrite it. - (fopen_case): Remove this function. - (locate_file_in_dir): New function. - * cvs.h (locate_rcs): Prototype new function. - * rcs.c (RCS_parse): Factor out file location into locate_rcs. - -2003-03-17 Larry Jones <lawrence.jones@eds.com> - - * server.c (switch_to_user): Add syslog calls for setgid/setuid - failure. - -2003-03-07 Derek Price <derek@ximbiot.com> - - * sanity.sh (help): Add explanation of CVS-TO-TEST and edit for - consistency. - -2003-03-07 Derek Price <derek@ximbiot.com> - - * sanity.sh (usage): Show users long --help rather than less - informative -h. - -2003-03-07 Derek Price <derek@ximbiot.com> - - * sanity.sh: Add support for long options. - (exit_usage): Move the actual generation of usage text to... - (usage): ...this new function and improve the usage message. - (exit_help): New function. - -2003-03-07 Larry Jones <lawrence.jones@eds.com> - - * commit.c (check_fileproc): Remove unused variables. - - * patch.c (patch): Pass local to do_module so that -l actually works. - (Reported by John Coers <coers@intrinsity.com>.) - (patch_fileproc): Fix uninitialized variables. - * sanity.sh: Define a DATE pattern for rdiff and use it. - (basic2-24a): New test for above. - -2003-03-06 Derek Price <derek@ximbiot.com> - - * subr.c (file_has_conflict): New file. - * commit.c (check_fileproc): Factor code into new file_has_conflict() - function. - * update.c (update_fileproc): Ditto. - * status.c (status_fileproc): Use new file_has_conflict() function. - (Report from Bernd Kuemmerlen <bkuemmer@mevis.de>.) - - * sanity.sh (status): New test for same. - -2003-03-05 Mark D. Baushke <mdb@cvshome.org> - - * rcs.c (RCS_magicrev): Backout CVS_LOCAL_BRANCH_NUM feature. - - * rcs.c (RCS_magicrev): CVS_LOCAL_BRANCH_NUM feature. - Port of the FreeBSD hack for setting the next magic branch number - to be used. The original patch was written by Peter Wemm - <peter@FreeBSD.org> and may be found by visiting the URL: - http://www.freebsd.org/cgi/cvsweb.cgi/src/contrib/cvs/src/rcs.c.diff?r1=1.1&r2=1.2 - Implement a horrible (but simple) hack to allow some control over the - branch number that is assigned. This is specifically to support the - local commit feature of cvsup. If one sets $CVS_LOCAL_BRANCH_NUM to - (say) 1000 then branches the local repository, the revision numbers - will look like 1.66.1000.xx. This is almost a dead-set certainty that - there will be no conflicts with version numbers. - (This needs to be something more than an option to 'cvs tag' or 'cvs - rtag' as various parts of cvs "know" how to automatically branch files - (eg: cvs add). Trying to remember state is getting "Too Hard (TM)") - * sanity.sh (branches3): Test the CVS_LOCAL_BRANCH_NUM feature. - -2003-03-04 Derek Price <derek@ximbiot.com> - - * history.c (history_write): Remove unneeded O_CREAT in the call to - open() since we abort a few lines earlier if the file doesn't exist. - Add a comment to the effect that this is not the optimal method of - doing things and needs fixed. - -2003-02-28 Derek Price <derek@ximbiot.com> - - * root.c (parse_cvsroot): s/no_passwd/no_password/ in comments. - -2003-02-28 Derek Price <derek@ximbiot.com> - - * root.c (parse_cvsroot): Set no_password for :gserver: and :kserver: - as tokens should already be obtained via external sources. - * update.c (update_fileproc): Remove redundant code. - -2003-02-28 Larry Jones <lawrence.jones@eds.com> - - * lock.c (set_lock): If possible, try a short wait with no message - before calling lock_wait() to optimize master lock contention. - -2003-02-26 Larry Jones <lawrence.jones@eds.com> - - * checkout.c (checkout): Send "--" before file names. - * sanity.sh (spacefiles): Remote now works just like local. - -2003-02-25 Derek Price <derek@ximbiot.com> - - * sanity.sh (rcs4): Use UTC to work across timezones. - -2003-02-25 Derek Price <derek@ximbiot.com> - - * rcs.c (RCS_getdate): Fix a bug that shows up when checking out - files by date with the "-D date" command line option. There is - code in the original to handle a special case. If the date search - finds revision 1.1 it is supposed to check whether revision - 1.1.1.1 has the same date stamp, which would indicate that the - file was originally brought in with "cvs import". In that case it - is supposed to return the vendor branch version 1.1.1.1. - - However, there was a bug in the code. It actually compares the date - of revision 1.1 for equality with the date given on the command - line -- clearly wrong. This commit fixes the coding bug. - - Note: There is an additional bug which is _not_ fixed in this - commit. The date comparison should not be a strict equality test. - It should allow a fudge factor of, say, 2-3 seconds. Old versions - of CVS created the two revisions with two separate invocations of - the RCS "ci" command. We have many old files in the tree in which - the dates of revisions 1.1 and 1.1.1.1 differ by 1 second. - - This bug was discovered and fixed for FreeBSD cvs. See v 1.21 of - <http://www.freebsd.org/cgi/cvsweb.cgi/src/contrib/cvs/src/rcs.c.diff> - for more information. - - * sanity.sh (rcs4): Tests for same. - (Patch from Mark D. Baushke <mdb@cvshome.org>.) - -2003-02-25 Derek Price <derek@ximbiot.com> - - * logmsg.c (logfile_write): Do not pass a NULL pointer to - fprintf() when we have an empty log message. - * sanity.sh (editor): Add new tests to verify correct behavior of - empty log messages. - (Patch from Mark D. Baushke <mdb@cvshome.org>, original report from - Piotr KUCHARSKI <chopin@sgh.waw.pl>.) - -2003-02-25 Derek Price <derek@ximbiot.com> - - * cvsbug.in: Import use of mktemp function from RedHat 8.0's - CVS 1.11.2 RPM. Use new MKTEMP configure variable. Use new - SENDMAIL from configure. - - * Makefile.in: Regenerated. - -2003-02-25 Derek Price <derek@ximbiot.com> - - * watch.c (watch_usage): Use {} rather than () for literals. - -2003-02-14 Derek Price <derek@ximbiot.com> - - * watch.c (watch_usage): Make the repeatability of -a part of the - usage spec. - -2003-02-14 Derek Price <derek@ximbiot.com> - - * watch.c (watch_usage): Mention default for -a. Mention multiple - invocations of -a. Mention -R as default. Use required () rather than - optional [] around watch subcommand list in invocation spec. Use - `path' instead of `file'. Put variable <> around `action' and `path'. - -2003-02-07 Derek Price <derek@ximbiot.com> - - * commit.c (checkaddfile): Do not lose the vendor branch when - adding files to a new branch. Avoids extranious conflicts for - future vendor imports. This was found and fixed in FreeBSD cvs. - See http://www.freebsd.org/cgi/query-pr.cgi?pr=4033 for details. - * sanity.sh (branch-after-import): New test. - (Thanks to Mark D Baushke <mdb@cvshome.org> for forwarding the - patch and writing the test cases!) - - * sanity.sh (branch-after-import): Misc portablility and standard - changes. - -2003-02-12 Derek Price <derek@ximbiot.com> - - * main.c (main): Update copyright message to 2003. - -2003-02-21 Larry Jones <lawrence.jones@eds.com> - - * server.c (switch_to_user): Update comment, change error message - so it's not an exact duplicate of the one in check_password. - (check_repository_password): Add syslog call for password mismatches. - (check_password): Add syslog call for password mismatches, rearrange - code to simplify and eliminate redundancy. - (pserver_authenticate_connection): Remove syslog call, now done by - lower-level routines. - -2003-02-19 Larry Jones <lawrence.jones@eds.com> - - * sanity.sh (admin-10): Add test for repository files not in - working directory. - - * admin.c (admin_fileproc): Fix crash when no rcs file, return - failure status for bogus files. - * sanity.sh (admin-4a): Test for above. - (Original patch submitted by Mark D. Baushke <mdb@cvshome.org>). - -2003-02-14 Larry Jones <lawrence.jones@eds.com> - - * log.c (log_expand_revlist): Fix crashes in error cases. - (Reported by Bart Santy <Bart.Santy@switch.be>.) - * sanity.sh (log): New tests for above. - -2003-02-01 Larry Jones <lawrence.jones@eds.com> - - * buffer.c (stdio_buffer_shutdown): Handle EINTR from waitpid. - (Patch from Johannes Grødem <johs+n@ifi.uio.no>.) - -2003-02-08 Derek Price <derek@ximbiot.com> - - * rcs.c (RCS_checkout): Supply the full function name in the trace - output. - * update.c (checkout_file, join_file): Supply tag properly to - RCS_checkout more often. - (patch_file): Ditto. Fill out comments. - * sanity.sh (keyword, keywordname): Some changes to accomodate the fact - that the above changes cause patches generated by patch_file to fail - occassionally. - -2003-02-06 Derek Price <derek@ximbiot.com> - - * client.c: Use the complete path to the CVSADM_TEMPLATE file in - error messages. Remove related FIXME. - -2003-01-31 Derek Price <derek@ximbiot.com> - - * sanity.sh (keywordname): Change a "FIXME" comment to "FIXCVS". - -2003-01-30 Derek Price <derek@ximbiot.com> - - * sanity.sh (keywordname): New test. - -2003-01-23 Larry Jones <lawrence.jones@eds.com> - - * diff.c (diff_fileproc): Restructure code to simplify and eliminate - redundant tests. - - * server.c (do_cvs_command): Use WCOREDUMP macro rather than hard - coding test for core file. - -2003-01-21 Larry Jones <lawrence.jones@eds.com> - - * root.c (method_name): Redefine as a 2D array. - * root.h (method_name): Ditto. - -2003-01-21 Jim Meyering <jim@meyering.net> - - * add.c (add): Rename local-shadowing `i' to `j'. - - * root.c (method_names): Declare to be a const array of const strings. - (Name_Root): Save errno so it doesn't get clobbered - by the intervening error call. - Use getline's return value, mainly to save a call to strrchr. - -2003-01-20 Larry Jones <lawrence.jones@eds.com> - - * myndbm.c (O_ACCMODE): Parenthesize the replacement string so that - it parses correctly. - (Reported by Andres Bertens <abertens@entelchile.net>.) - -2003-01-15 Karl Fogel <kfogel@collab.net> - - * server.c (dirswitch): Don't free dir_name until right before - allocating it again. This removes a potential double-free - problem, whereby this function could free dir_name and then - immediately return due to invalid directory syntax (without ever - reassigning dir_name), then reenter and free dir_name again. - - Thanks to Stefan Esser <s.esser@e-matters.de> for the fix. - -2003-01-08 Larry Jones <lawrence.jones@eds.com> - - * client.c (update_entries): Only "0" is a special version number; - other numbers starting with 0 (like 0.1) are normal version numbers. - * commit.c (find_fileproc): Ditto. Also reorganize the code to - simplify the conditions. - (Reported by Michele Zamparelli <michele.zamparelli@eso.org>.) - -2003-01-02 Larry Jones <lawrence.jones@eds.com> - - * rcs.c (getdelta): Use RCSDEAD rather than literal "dead". - -2002-12-27 Derek Price <derek@ximbiot.com> - - * admin.c: s/LOCK_(NONE|WRITE|READ)/CVS_$&/g; since the definition of - LOCK_WRITE clashes with a definition in objidl.h on Windoze platforms. - * annotate.c: Ditto. - * client.c: Ditto. - * commit.c: Ditto. - * cvs.h: Ditto. - * diff.c: Ditto. - * edit.c: Ditto. - * lock.c: Ditto. - * log.c: Ditto. - * patch.c: Ditto. - * recurse.c: Ditto. - * remove.c: Ditto. - * status.c: Ditto. - * tag.c: Ditto. - * update.c: Ditto. - * watch.c: Ditto. - * myndbm.c: Ditto & define O_ACCMODE when it isn't defined, as under - Windoze. - (Thanks to Stephane Rouleau <s.rouleau@videotron.ca>, - Cristopher Seawood <cls@seawood.org>, and - Frederico Costa <frederico.costa@tiscali.no> for all their hints, - tips, and patches for this problem.) - -2002-12-20 Derek Price <derek@ximbiot.com> - - * client.c (send_a_repository): Suppress a warning under Windoze. - -2002-12-19 Derek Price <derek@ximbiot.com> - - * Makefile.am: Remove reference to options.h. - * cvs.h: Ditto. - * options.h: Remove this obsolete file. - * sanity.sh: Remove comment about external diffs causing tests to fail - since CVS hasn't used external diffs in years. - - * Makefile.in: Regenerated. - -2002-12-16 Derek Price <derek@ximbiot.com> - - * admin.c: Disable cvsadmin group checking on the client. - (Reported by Dan Peterson <dbpete@aol.com>.) - -2002-12-06 Derek Price <derek@ximbiot.com> - - * buffer.c: Replace calls to malloc with calls to xmalloc and calls to - realloc with calls to xrealloc. - * parseinfo.c: Ditto. - * root.c: Ditto. - * server.c: Ditto. - * zlib.c: Ditto. - * scramble.c: Change some comments to refer to xmalloc rather than - malloc. - (Reported by Dan Peterson <dbpete@aol.com>.) - -2002-12-04 Derek Price <derek@ximbiot.com> - - * options.h: Remove CVS_ADMIN_GROUP. - -2002-12-02 Larry Jones <lawrence.jones@eds.com> - - * commit.c (commit): Strip leading zeros from numeric revision - in addition to trailing dots. - (Reported by Peter Meszaros <pme@prolan.hu>.) - -2002-11-22 Larry Jones <lawrence.jones@eds.com> - - * sanity.sh: Note that the tests run for a long time. - - * checkout.c (safe_location): Use xstrdup, not strdup. - (Reported by Terrence Enger <tenger@iSeries-guru.com>.) - -2002-11-19 Larry Jones <lawrence.jones@eds.com> - - * log.c (log_expand_revlist): Fix cross-branch correction code. - - * sanity.sh: Set $LANG for systems that ignore $LC_ALL. - (rcs2-7): Change date offset from 100 months to 96 months to reduce - periodic problems with invalid dates. - -2002-11-12 Derek Price <derek@ximbiot.com> - - * sanity.sh (rcslib-symlink): Use rm -f rather than a simple rm when - removing links because under some configurations of RH Linux 8.0 the - script pauses to ask for removal approval. - -2002-11-08 Derek Price <derek@ximbiot.com> - - * sanity.sh (importc): Update the use of the touch command to be - compliant with POSIX 1003.1-2001, SUS2, and SUS3 now that GNU touch - supports this. If this breaks any test platforms we should test - the behavior of touch like we do for other tools. - -2002-11-03 Derek Price <derek@ximbiot.com> - - * sanity.sh (rcs2-7): Notate with a wild untested hypothesis. - -2002-11-03 Derek Price <derek@ximbiot.com> - - * sanity.sh (rcs2-7): Notate with three more failure dates. - -2002-10-25 Derek Price <derek@ximbiot.com> - - * root.c: Change some calls to SYSTEM_CLEANUP() and then exit() to - more appropriate calls to error_exit(). - * server.c: Ditto. - * tag.c: Ditto. - -2002-10-24 Derek Price <derek@ximbiot.com> - - * buffer.c (stdio_buffer_shutdown): Remove the getc() call used to - detect spurious output from clients since getc() would sometimes - block and hang indefinately if the client kept the conection open but - sent no data. Bug reports state that this hapened frequently with - older clients connecting to 1.11.2 servers, especially when - compression is enabled. - (Original report from Mark D. Baushke <mdb@juniper.net>. - Original patch from Ralf S. Engelschall <rse@engelschall.com> - via Peter Wemm <peter@freebsd.org>.) - -2002-10-05 Larry Jones <lawrence.jones@eds.com> - - * recurse.c (start_recursion, do_recursion): Allow write locking - in addition to read locking. Change all callers. - * cvs.h: Change prototype to match, add lock types. - * tag.c (rtag_proc, rtag_fileproc, tag_fileproc): Have start_recursion - use write locks rather than calling lock_dir_for_write to avoid deadly - embrace. - -2002-10-04 Larry Jones <lawrence.jones@eds.com> - - * client.c (get_responses_and_close, connect_to_pserver): Set - to_server and from_server to NULL after freeing. - * main.c (main): Clear server_active when finished. Also neaten - up the SERVER_SUPPORT ifdef's. - * server.c (do_cvs_command): Set protocol_inbuf, stderrbuf, and - stdoutbuf to NULL after freeing. - (server_cleanup): Free buf_from_net and buf_to_set and set to NULL. - Also reset error_use_protocol. - (server): Don't SIG_register server_cleanup. main_cleanup (which - is already registered) outputs a fatal error which causes it to - be called; registering it directly results in it being called twice. - (cvs_output): Don't try to use buf_to_net or protocol if they're NULL. - -2002-10-03 Larry Jones <lawrence.jones@eds.com> - - * lock.c (readers_exist): Ignore our own read lock, if any, to - allow upgrading an existing read lock to a write lock. - * tag.c (rtag_proc, rtag_fileproc, tag_fileproc): Rather than - locking the entire tree, have start_recursion establish read - locks and then upgrade the read lock to a write lock (so only - one directory is locked at a time). - -2002-09-27 Larry Jones <lawrence.jones@eds.com> - - * add.c (add): Send "--" before file names. - * admin.c (admin): Ditto. - * annotate.c (annotate): Ditto. - * commit.c (commit): Ditto. - * diff.c (diff): Ditto. - * edit.c (watch_onoff, editors): Ditto. - * log.c (cvslog): Ditto. - * remove.c (cvsremove): Ditto. - * status.c (cvsstatus): Ditto. - * tag.c (cvstag): Ditto. - * update.c (update): Ditto. - * watch.c (watch_addremove, watchers): Ditto. - - * sanity.sh (client-9): Update to match. - -2002-09-24 Derek Price <derek@ximbiot.com> - - * options.h: Remove prototype of STDC exit() function. If this breaks - a build, this should be detected in configure.in somehow rather than - restoring the line to this file. - -2002-09-24 Derek Price <derek@ximbiot.com> - - * options.h: Move definition of AUTH_CLIENT_SUPPORT into configure.in. - -2002-09-24 Derek Price <derek@ximbiot.com> - - * options.h: Move definition of FORCE_USE_EDITOR into configure.in. - -2002-09-24 Derek Price <derek@ximbiot.com> - - * options.h: Move definition of UMASK_DFLT into configure.in. - -2002-09-24 Derek Price <derek@ximbiot.com> - - * Makefile.in: Regenerated using Automake 1.6.3. - -2002-09-24 Larry Jones <lawrence.jones@eds.com> - - * filesubr.c, history.c, import.c, rcs.c, update.c: Use - HAVE_STRUCT_STAT_ST_BLKSIZE and HAVE_STRUCT_STAT_ST_RDEV instead of - the obsolete HAVE_ST_BLKSIZE and HAVE_ST_RDEV. - -2002-09-24 Derek Price <derek@ximbiot.com> - - * options.h: Move definition of TMPDIR_DFLT into configure.in. - -2002-09-24 Derek Price <derek@ximbiot.com> - - * options.h: Move defininition of EDITOR_DFLT into configure.in. - - * Makefile.in: Regenerated. - -2002-09-23 Jim Meyering <meyering@lucent.com> - - If `cvs -d REPO commit ...' was used to override CVS/Root, - then modified files in the directory from which cvs is invoked - would not be committed. - * client.c (arg_should_not_be_sent_to_server): The above would happen - because this function would throw out a file name when CVS/Root - did not match the current server. Fix by allowing the command-line- - specified repository to take precedence over the value returned - by Name_Root. Patch by Simon Walton <simonw@lucent.com>. - * sanity.sh (commit-d): New tests for the above. - Patch by Simon Walton <simonw@lucent.com>. - -2002-09-20 Derek Price <derek@ximbiot.com> - - * options.h: Move definition of SERVER_FLOWCONTROL, SERVER_HI_WATER, - and SERVER_LO_WATER into configure.in. - -2002-09-20 Derek Price <derek@ximbiot.com> - - * options.h: Move definition of PATCH_PROGRAM to configure.in. - -2002-09-18 Larry Jones <lawrence.jones@eds.com> - - * client.c (call_in_directory): Don't create admin directory when - exporting into an existing directory. - (Reported by Jens Engel <Jens.Engel@marconi.com>.) - * sanity.sh (basic2): New tests for above. - -2002-09-16 Jim Meyering <meyering@lucent.com> - - * server.c (do_cvs_command): Move declarations of locals, timeout and - timeout_ptr, `up', out of enclosing `#ifdef SERVER_FLOWCONTROL' block. - Otherwise, this file would not compile with SERVER_FLOWCONTROL - turned off. Patch by Ed Santiago <esm@ascend.com>. - -2002-09-15 Larry Jones <lawrence.jones@eds.com> - - * myndbm.c (mydbm_open): Open the file read/write rather than read- - only if that's what the user asked for to ensure that the later open - for write will succeed. - (Patch submitted by Josh Lehan <cvs@krellan.com>.) - -2002-08-28 Larry Jones <lawrence.jones@eds.com> - - * logmsg.c (do_editor): Fix bug which prevented reusing log messages. - (Reported by Eric Siegerman <erics@telepres.com>.) - -2002-08-16 Derek Price <derek@ximbiot.com> - - * create_adm.c (Create_Admin): Assume RELATIVE_REPOS is set. - * server.c (outside_root): Add comment. - * options.h: Remove RELATIVE_REPOS & CVS_BADROOT. - * sanity.sh: Remove a lot of !RELATIVE_REPOS cruft from tests. - -2002-08-14 Derek Price <oberon@umich.edu> - - * server.c (server): Dispose of the correct pointer. Tidy comment. - -2002-08-13 Derek Price <oberon@umich.edu> - - * client.c (get_cvs_port_number): Fix typo in comment. Add comments. - * server.c (server): Fix a FIXME. Remove an errant "const" directive. - Remove some redundant memory allocation and error handling code. - -2002-08-08 Derek Price <oberon@umich.edu> - - * import.c (import): Surrounded `server_active' with - #ifdef SERVER_SUPPORT/#endif. - * commit.c (commit_fileproc, commit_direntproc): Likewise. - (Patch from John Tytgat <John.Tytgat@aaug.net>.) - -2002-07-31 Derek Price <oberon@umich.edu> - - * filesubr.c: Add a line so VIM can determine tab stops and shift widths. - * root.c: Ditto. - * (parse_cvsroot): Add comments and tidy slightly. - -2002-07-31 Derek Price <oberon@umich.edu> - - * sanity.sh: Add another date to the comment about rcs2-7 failing. - -2002-07-26 Jim Meyering <meyering@lucent.com> - - * commit.c (find_fileproc): When committing in client mode, - arrange to fail if a `cvs add'ed file no longer exists in the - working directory. - * sanity.sh (commit-add-missing): New test for above. - -2002-07-25 Larry Jones <lawrence.jones@eds.com> - - * sanity.sh: Set $TMPDIR if it's not already set and use it rather - than /tmp for the expected server temp directory path. - -2002-07-09 Larry Jones <lawrence.jones@eds.com> - - * vers_ts.c (time_stamp_server, time_stamp): Eliminate unneeded - struct_tm copying. - - * lock.c (lock_wait, lock_obtained): Display time in UTC if possible - to reduce confusion in client/server mode. - (Original patch from Eduardo Perez Ureta <eperez@it.uc3m.es>.) - -2002-06-26 Larry Jones <lawrence.jones@eds.com> - - * tag.c (check_fileproc): When checking up-to-date, T_REMOVE_ENTRY - is also a valid status. - (Reported by David Everly <David.Everly@wcom.com>.) - * sanity.sh (tagc): New tests for above. - -2002-06-18 Larry Jones <lawrence.jones@eds.com> - - * update.c (patch_file): Don't patch if diff bigger than file. - Don't bother adjusting the permission on the diff output if - we're not going to use it. - - -2002-06-18 Derek Price <oberon@umich.edu> - - * server.c: Handle HPUX password expiration fields in the passwd - string in case we are set up on a server with NIS passwords served - from HPUX. - (Original patch from John Cavanaugh <john_cavanaugh@agilent.com>.) - -2002-06-17 Larry Jones <lawrence.jones@eds.com> - and Jonathan Kamens <jik@kamens.brookline.ma.us> - - * commit.c (commit_fileproc, commit_direntproc): Don't try to call - an editor to get the log message if running as a server. Instead, - just use an empty log message. - * import.c (import): Ditto. - - * import.c (import): In client mode, always send a message to the - server, even if it's empty (this parallels a change made by Larry - Jones to commit.c on May 7). - -2002-05-31 Larry Jones <lawrence.jones@eds.com> - - * rcs.c: Conditionally define MAP_FAILED for old systems that don't - have it in <mman.h>. - (Reported by jeremy brand <jeremy@earth.care2.com>.) - -2002-05-24 Larry Jones <lawrence.jones@eds.com> - - * rcscmds.c (diff_exec): Add a -- before the first file name just - in case it looks like an option. - (Reported by Zooko <zooko@zooko.com>.) - - * rcscmds.c (diff_execv): Remove -- same as diff_exec. Change - only caller. - * cvs.h: Ditto. - -2002-05-23 Larry Jones <lawrence.jones@eds.com> - - * cvs.h (strcat_filename_onto_homedir): Make arguments const. - * filesubr.c (strcat_filename_onto_homedir): Make arguments const, - move more code here from callers, change all callers. - -2002-05-22 Derek Price <oberon@umich.edu> - - * cvs.h: Add prototype for this... - * filesubr.c (strcat_filename_onto_homedir): new function. - * login.c (): Use new function. - - * cvsrc.c (read_cvsrc): Use new function due to problems on VMS. - * ignore.c (ign_setup): Ditto. - * wrapper.c (wrap_setup): Ditto. - (Original patch from Karsten Spang <ksp@dannet.dk>.) - -2002-05-21 Larry Jones <lawrence.jones@eds.com> - - * rcs.c (rcsbuf_getkey): Correct off-by-one error in ptr assertion - and add a similar assertion for ptrend. - (Reported by Rebecca Young <raygirl@cvshome.org>.) - (rcsbuf_fill): Remove redundant code. - -2002-05-20 Derek Price <oberon@umich.edu> - - * buffer.h: New prototype for... - * buffer.c (stdio_buffer_get_file): this new function to abstract - access to a buffer's file descriptor. - * client.c (auth_server): Use the new function. - (Original patch from Jonathan Kamens <jik@kamens.brookline.ma.us>.) - -2002-05-20 Derek Price <oberon@umich.edu> - - * main.c (main): Add 2002 to the copyright years output with the - version string. - -2002-05-15 Larry Jones <lawrence.jones@eds.com> - - * log.c (log_parse_list): Fix off-by-one error which caused - incorrect handling of 'cvs log -wuser1,user2 foo.c' command. - (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>, - reported by Alex Morozov <morozov@novosoft.ru>.) - -2002-05-09 Larry Jones <lawrence.jones@eds.com> - - * login.c (password_entry_operation): Get cvsroot_canonical before - trying to read the user's password file so we have it even if the - file doesn't exist. - (Reported by Sarah Thompson <sthompson@fsl.noaa.gov>.) - -2002-05-08 Derek Price <oberon@umich.edu> - - * Makefile.am (cvs_SOURCES): Add options.h explicitly - since we - stopped generating it dynamically, Automake stopped noticing it and - including it in dists. See TODO item #214 for notes. - -2002-05-08 Derek Price <oberon@umich.edu> - - * cvs.h: Use the HAVE_CONFIG_H define. - -2002-05-07 Larry Jones <lawrence.jones@eds.com> - - * filesubr.c (isaccessible): Set errno before returning failure - in the SETXID_SUPPORT code. - - * logmsg (do_verify): Avoid even more work if there's no verifymsg - script to run. - - * logmsg: Use fputs/putc rather than fprintf where appropriate. - (do_verify): Run the verifymsg script even if there's no log - message. (Reported by Andy Baker <Andy.Baker2@t-mobile.co.uk>.) - Don't reread the log message unless a verifymsg script was run. - - * commit.c (commit): Always send -m to the server, even if there's - no message. - - * create_adm.c (Create_Admin): Add dotemplate parameter to trace. - Remove unreachable code. - -2002-05-03 Larry Jones <lawrence.jones@eds.com> - - * server.c (serve_watch_on, serve_watch_off, serve_watch_add, - serve_watch_remove): Just pass "watch" as the command name - to do_cvs_command to avoid unknown command errors. - (Reported by Gary Hennigan <gary@ieee.org>.) - - * rcs.c (RCS_checkin): Fix bad call to error () in buggy - PRESERVE_PERMISSIONS code. - (rcs_internal_unlockfile): Include current value of errno in error - message even though it may well be irrelevant (it's still better - than nothing). - -2002-05-02 Derek Price <oberon@umich.edu> - - * .cvsignore: Remove lines for files obsoleted by new autotools. - -2002-05-02 Derek Price <oberon@umich.edu> - - * stamp-h2.in: Remove this uneeded file. - -2002-05-01 Derek Price <oberon@umich.edu> - - * options.h.in: Move to... - * options.h: here. - -2002-04-30 Derek Price <oberon@umich.edu> - - * version.h.in: Remove this file. - * version.h: Ditto. - - * Makefile.am: Remove references to version.h. - * cvs.h: Use <> rather than "" around the config.h #include. I didn't - quite bother to understand why, but autoconf recommends it. - * cvsbug.in: Use PACKAGE_BUGREPORT defined by configure for the bug - report email address. - * version.c (version): Use PACKAGE_STRING defined in config.h instead - of the version_string that used to be defined in version.h. - - * Makefile.in: Regenerated with automake 1.6. - -2002-04-28 Derek Price <oberon@umich.edu> - - * cvs.h: Use `"'s around includes when we mean a local file. - -2002-04-28 Derek Price <oberon@umich.edu> - - * cvs.h: #define new names for functions and variables when they - might conflict with system definitions (namely on Mac OS X 10.1 with - the most recent dev packages - This should be removable after the Mac - dev packages are fixed.). - -2002-04-26 Larry Jones <larry.jones@sdrc.com> - - * logmsg.c (do_editor): Fix assertion when CLIENT_SUPPORT not defined. - (Reported by Matthias Andree <matthias.andree@stud.uni-dortmund.de>.) - -2002-04-19 Larry Jones <larry.jones@sdrc.com> - - * log.c (log_expand_revlist): First cut at code to allow logging - between a revision and *any* ancestor, not just one explicitly on - the same branch (e.g., from 1.1 to 4.1.2.3.6.1). - - * subr.c (gca): Simplify and optimize. - -2002-04-19 Jim Meyering <meyering@lucent.com> - and Ed Santiago <easm@lucent.com> - - * classify.c (Classify_File): Fix it so that `cvs update -p -r...' - works, even under some slightly unusual (though perfectly legitimate) - circumstances. - * sanity.sh (update-p): New tests for this. - -2002-04-18 Derek Price <oberon@umich.edu> - - * sanity.sh: Move test for regex metacharacters in username until - after we're sure we found the version of expr that we're going to use. - -2002-04-18 Larry Jones <larry.jones@sdrc.com> - - * admin.c (admin_fileproc): Allow admin to be used on RCS files with - no local version (e.g., removed files) like most other subcommands. - - * wrapper.c (wrap_add): Update URL of -t/-f wrapper discussion. - -2002-04-18 Derek Price <oberon@umich.edu> - - * version.h: Regenerated for 1.11.2.1 version update. - -2002-04-17 Derek Price <oberon@umich.edu> - - * version.h: Regenerated for 1.11.2. - -2002-04-03 Derek Price <oberon@umich.edu> - - * stamp-h2.in: Regenerate with recent version of Autoconf. - -2002-04-03 Derek Price <oberon@umich.edu> - - * sanity.sh (TR): Send the stderr of one of the tool setup (tr) tests - to /dev/null to avoid spurious output on some operating systems - (notably Mac OS X). - -2002-03-22 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (rcslib): Correct new tests to use ${testcvs} instead - of cvs. - -2002-03-21 Derek Price <oberon@umich.edu> - - * vers_ts.c (time_stamp): Return the timestamp for the newer of the - link and the link's source when the file is a link. - (Patch from RedHat cvs-1.11.1p1-7 SRPM.) - - * sanity.sh (rcslib): Test for same. - -2002-03-17 Larry Jones <larry.jones@sdrc.com> - - * log.c (cvslog, log_fileproc): Add -S option to suppress head or - file name if no revisions selected. - * sanity.sh (log): New tests for above. - -2002-03-13 Derek Price <oberon@umich.edu> - - * main.c (usg): Correct a spelling mistake in a comment. - (Thanks to Matt Kraai <kraai@alumni.cmu.edu>.) - -2002-03-09 Larry Jones <larry.jones@sdrc.com> - - * import.c (import): Change the suggested merge message to use - rev tags instead of the branch tag with a date. - * sanity.sh (import, importb): Change to match. - - * remove.c (remove_fileproc): Disallow removing files with sticky - dates for the same reason we already disallow sticky numeric tags. - * sanity.sh (sticky): New test for above. - -2002-02-27 Larry Jones <larry.jones@sdrc.com> - - * diff.c (diff_fileproc): Treat dead revisions as nonexistent. - -2002-02-26 Larry Jones <larry.jones@sdrc.com> - - * diff.c (diff): Remove -V and --paginate options: they aren't valid. - (diff_usage): Document all the diff options. - -2002-02-13 Larry Jones <larry.jones@sdrc.com> - - * rcs.c (RCS_gettag): Do not interpret an empty tag as HEAD (nothing - else does and I don't see any documentation that says it should). - (translate_symtag): Break out of loop at end of symbols to prevent - looping forever when tag is "". - (Reported by Alain ENOUT <aln00@udcast.com> - via Eric Gillespie <epg@pretzelnet.org>.) - -2002-02-11 Larry Jones <larry.jones@sdrc.com> - - * server.c (server_cleanup): Set buf_to_net back to blocking mode - and flush it (in case there are any error messages pending) before - shutting down buf_from_net and again right before shutting it down. - -2002-02-08 Larry Jones <larry.jones@sdrc.com> - - * main.c (lookup_command_attribute): Throw a fatal error if the - command is not found. - * server.c (server_tag): Use the correct command name. - -2002-01-30 Larry Jones <larry.jones@sdrc.com> - - * error.h (error_exit): Remove unintended prototype. - - * server.c (serve_root): Remove check for impossible condition. - (serve_init): Save and restore current_parsed_root. - -2002-01-29 Larry Jones <larry.jones@sdrc.com> - - * error.h (error_exit): Declare __noreturn__ to avoid spurious - warnings. - - * server.c (serve_root): If the specified root doesn't match the - pserver root, return before changing current_parsed_root to prevent - subsequent commands from accessing an unchecked root directory. - (server_init): Check specified root against the pserver root and - complain if they don't match. Also, if there are pending errors, - print them and return before changing current_parsed_root to prevent - subsequent commands from accessing an unchecked root directory. - * sanity.sh (pserver): New tests for above. - -2002-01-10 Larry Jones <larry.jones@sdrc.com> - - * log.c (log_version_requested): Change :: in revision spec to be - exclusive just on the low end (so -r tag1::tag2 gives revisions - after tag1 but up to and including tag2), which is much more useful - than the previous (exclusive at both ends) behavior. - (log_usage): Update to match. - * sanity.sh (log): Update to match. - -2002-01-02 Larry Jones <larry.jones@sdrc.com> - - * server.c (LOG_DAEMON): Define if needed. - (Patch from John David Anglin <dave@hiauly1.hia.nrc.ca>.) - - * server.c (pserver_authenticate_connection): Add a specific error - message for EOF at protocol start and syslog if available. - * sanity.sh (pserver-bufinit): Update to match. - -2001-12-10 Larry Jones <larry.jones@sdrc.com> - - * log.c (log_usage): Note that -r and -d take lists, not just a - single specification. - (log_expand_revlist): Don't dereference null pointers when one end - of a revision range is a non-existent tag. - -2001-12-03 Larry Jones <larry.jones@sdrc.com> - - * annotate.c (annotate, annotate_fileproc): Don't annotate binary - files unless new -F option given. - * sanity.sh (basica, ann, ann-id, rcs, keywordlog, tagdate): Update - to match. - -2001-11-30 Larry Jones <larry.jones@sdrc.com> - - * admin.c (admin): Allow unrestricted usage of -q in addition to -k. - -2001-10-25 Larry Jones <larry.jones@sdrc.com> - - * log.c (log_expand_revlist): Make erroneous or inconsistent revision - specs select no revisions rather than all revisions. - -2001-10-23 Larry Jones <larry.jones@sdrc.com> - - * import.c (add_rcs_file): Don't put an expand entry into the file - for the default expansion mode (kv). - * wrapper.c (wrap_send, wrap_unparse_rcs_options): Process entries - with default expansion mode since they may be needed to avoid matching - a more general entry later. - (wrap_add): Set rcsOption to NULL for default (kv). - (wrap_add_entry): Use structure assignment to copy entries rather - that copying members by hand. - * sanity.sh (binwrap3): Revise to test wrapper entries that don't - specify any non-default options but just prevent matching later, - more general entries. - -2001-10-02 Larry Jones <larry.jones@sdrc.com> - - * rcs.c (RCS_fully_parse): Add revision number to more error messages. - -2001-09-27 Larry Jones <larry.jones@sdrc.com> - - * rcs.c (RCS_fully_parse, RCS_getdeltatext): Add the missing revision - number to the "mismatch" error message. - - * sanity.sh (multiroot2-9a): Update to match changes to lock.c. - -2001-09-26 Larry Jones <larry.jones@sdrc.com> - - * lock.c (Lock_Cleanup, Reader_Lock, write_lock): Add trace messages. - -2001-09-24 Derek Price <dprice@collab.net> - - * find_names.c (add_entries_proc): Leave closure specified as such in the - function definition for clarity. - - * find_names.c (Find_Names): Use 'closure' feature of walklist() - to eliminate the static variable. - (add_entries_proc): Expect closure to be the file list. - (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>.) - -2001-09-19 Derek Price <dprice@collab.net> - - * rcs.c (rcsbuf_valpolish_internal): Restore one of the - "if ( ... ) abort();" sequences since it seems to check the validity of - the RCS file rather than for a programming error. Also added a FIXME - comment to the effect that we should explain the RCS file error to the - user as such if it is such. - (Thanks to Larry Jones <scjones@sdrc.com>.) - -2001-09-19 Derek Price <dprice@collab.net> - - * rcs.c (rcsbuf_getkey, rcsbuf_valpolish_internal): Replace some code - of the form "if ( ... ) abort();" with equivalent calls to assert(). - -2001-09-17 Derek Price <dprice@collab.net> - - * myndbm.c (mydbm_load_file): Fix buffer overflow error and make error - messages more informative. - * sanity.sh (modules6): New test. - (Original report from Taska <taska@collab.net> and others.) - -2001-09-14 Derek Price <dprice@collab.net> - - * logmsg.c (do_verify): Dispose memory when finished with it. - -2001-09-07 Larry Jones <larry.jones@sdrc.com> - - * mkmodules.c (notify_contents): In the example, move the %s to - the end since many, if not most, versions of mail insist on - options coming before addresses. - -2001-09-06 Derek Price <dprice@collab.net> - - * login.c (login): Deal with NULL return value from getpass. - -2001-09-04 Derek Price <dprice@collab.net> - - * Makefile.in: Regenerated with automake 1.5. - * stamp-h2.in: Ditto. - -2001-09-04 Derek Price <dprice@collab.net> - - * main.c (main): Fix empty CVSROOT message to specify `valid' instead - of `legal'. - -2001-09-04 Derek Price <dprice@collab.net> - - * server.c (pserver_authenticate_connection): Back out changes from the - 30th and... - * getline.c (getstr): init the buffer instead. - -2001-08-31 Derek Price <dprice@collab.net> - - * Makefile.in: Backed out accidental commit from yesterday. - -2001-08-30 Derek Price <dprice@collab.net> - - * server.c (pserver_authenticate_connection): Don't print from the - NULL pointer in the error message string in the case where the client - didn't send any data. - * sanity.sh (pserver): Test for this case. - (Report from Mark Welch <mark@collab.net>). - -2001-08-24 Derek Price <dprice@collab.net> - - * logmsg.c (do_editor): Add comment and assertion. - * import.c (import): Don't call do_editor with a repository argument - in client mode. - (Report and original patch from darkness <darkness@invado.com>.) - -2001-08-24 Larry Jones <larry.jones@sdrc.com> - - * log.c (log_expand_revlist): Arrange for nil revision specs to - select nothing instead of everything. - * sanity.sh (log): New tests for above. - -2001-08-24 Derek Price <dprice@collab.net> - - * parseinfo.c (Parse_Info): Change the function name in the trace - and add the client/server string. - -2001-08-24 Derek Price <dprice@collab.net> - - * Implement RereadLogAfterVerify CVSROOT/config option to control - FreeBSD read-write of log messages in the verification script. - * logmsg.c: RereadLogAfterVerify defaults to LOGMSG_REREAD_NEVER - to preserve the status quo. - * parseinfo.c (parse_config): Add parsing for RereadLogAfterVerify - option. Possible values are: no | never | yes | always | stat - * cvs.h: Add extern for RereadLogAfterVerify and new value macros - LOGMSG_REREAD_NEVER, LOGMSG_REREAD_ALWAYS, LOGMSG_REREAD_STAT for - its values. - (Patch from Mark D. Baushke <mdb@cvshome.org>.) - - * Apply changes from FreeBSD cvs sources to implement a read-write - user-defined verification script. - * logmsg.c (do_verify): Update do_verify to expect a pointer - to the saved message. The log file passed to the verifymsg_script - should be re-read after the user-defined verification script has - been run. The user-defined verification script is allowed to - modify the message. This allows the script to add extra - information to the log message or to remove template lines that - are not needed. - * cvs.h: Update prototype for do_verify prototype to expect a - pointer to the saved_message. - * commit.c (commit, commit_fileproc, commit_direntproc): Update - calls to do_verify as the saved_message arg is now read-write. - * import.c (import): Update calls to do_verify as the - saved_message arg is now read-write. - * sanity.sh (info-v4-[12]): Rename the old info-v4 test to info-v5 - and add a new info-v4 test case have the verification script - modify the log message to test the above changes. - (Patch from Mark D. Baushke <mdb@cvshome.org>.) - - * logmsg.c: Change RereadLogAfterVerify default to always. - (do_verify): Reformat and make minor fixes to Mark's patch. - * mkmodules.c (config_constants): Add comment about - RereadLogAfterVerify. - * sanity.sh (info-rereadlog): Rename the tests from Mark's patch and - reformat them a bit. - -2001-08-23 Derek Price <dprice@collab.net> - - * sanity.sh (info): Demonstrate that the verifymsg scripts can - sometimes, but not always, retreive information on which directory is - being committed to. - -2001-08-22 Derek Price <dprice@collab.net> - - * logmsg.c: Back out the last change - the repository which is passed - in is actually the directory and changes with each call to do_verify. - If a verifymsg script is using `pwd`, this could change the operation. - * cvs.h: Ditto. - * commit.c: Ditto. - * import.c: Ditto. - -2001-08-22 Derek Price <dprice@collab.net> - - * logmsg.c (do_editor): Return reused_message. - (do_verify): Don't verify the same log message more than once. - * cvs.h: Update prototypes for do_verify and do_editor. - * commit.c (commit_fileproc, commit_direntproc): Use the new functionality. - * import.c (import): Ditto. - -2001-08-22 Derek Price <dprice@collab.net> - - * logmsg.c (do_verify): Remove an unecessary "else" clause following an - exit and unindent the former contents. - -2001-08-22 Derek Price <dprice@collab.net> - - * commit.c (commit): Don't call do_verify in client mode since we know - do_verify will just return anyhow. - -2001-08-20 Derek Price <dprice@collab.net> - - * Makefile.am (cvs_SOURCES): Add version.c and version.h. - (BUILT_SOURCES): Add version.h. - (Maintainer Targets): Remove version.h. - * version.c: Remove @VERSION@ dependant bits. - * version.c.in: Removed. - * version.h.in: New file. - (Original patch from Alexey Mahotkin <alexm@hsys.msk.ru>.) - - * Makefile.am: Various modifications to make Automake, make dist, and - windows targets work like they are supposed to. - * version.h: New (generated) file. - - * Makefile.in: Regenerated. - -2001-08-09 Derek Price <dprice@collab.net> - - * client.c (socket_buffer_shutdown): Use recv instead of read and - return 0 on success. - (Patch from "Manfred Klug" <manklu@web.de>.) - -2001-08-09 Derek Price <dprice@collab.net> - - * buffer.c (stdio_buffer_shutdown): Assume the buffer is not a socket - when NO_SOCKET_TO_FD is defined. - * client.c (make_bufs_from_fds): Add is_sock argument and remove fstat - call and reference to S_ISSOCK since these functions aren't available - under Windows. - (connect_to_forked_server, connect_to_pserver, start_tcp_server, - start_server, start_rsh_server): Use new argument. - (Patch from "Manfred Klug" <manklu@web.de>.) - - * buffer.c (stdio_buffer_shutdown): Various reformattings, fix bug - where rsh pipes weren't being closed. - -2001-08-09 Derek Price <dprice@collab.net> - - * sanity.sh (rmadd, rm-update-message, join-two-branch, - ignore-on-branch): Change a few references to `cvs' to `$PROG'. - -2001-08-07 Derek Price <dprice@collab.net> - - * build_src.com: Add annotate.c/annotate.obj,verify, correct zlib name. - * patch.c: VMS time_t appears to be unsigned. Add a cast when testing - for (time_t)-1. - * subr.c: #else,#endif for no symlinks should be moved. - (Patch from Mike Marciniszyn <Mike.Marciniszyn@sanchez.com>.) - -2001-08-06 Derek Price <dprice@collab.net> - - * Makefile.in: Regenerated. - -2001-08-01 Derek Price <dprice@collab.net> - - * diff.c (diff): Send long option for side-by-side diffs to the server - rather than '-y', for backwards compatibility with old servers. - (Original patch from Peter Mathiasson <peter@mathiasson.nu>.) - -2001-07-19 Larry Jones <larry.jones@sdrc.com> - - * mkmodules.c (cvswrappers_contents): Remove -t/-f since they're - disabled in wrapper.c. - - * checkout.c (checkout): Don't complain about checking out into the - repository when piping output. - (Reported by der Mouse <mouse@Rodents.Montreal.QC.CA>.) - * sanity.sh (checkout_repository): New tests for above. - -2001-07-10 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (importc-7): Now works correctly in local mode. - - * commit.c (commit_dirleaveproc): We're still in the directory when - this is called, so the first argument to Name_Repository needs to - be NULL, not dir. - * sanity.sh (rmadd): New tests for above. - - * commit.c (commit): Reword error messages for committing as root. - -2001-07-08 Larry Jones <larry.jones@sdrc.com> - - * rcs.c (RCS_checkout): Correct scanf format to allow for trailing - NUL terminator. - * update.c (special_file_mismatch): Ditto. - (Reported by Pekka Savola <pekkas@netcore.fi>.) - -2001-07-05 Larry Jones <larry.jones@sdrc.com> - - * client.c, root.c: Fix -Wall warnings. - - * buffer.c: #include socket header to declare shutdown(). - - * rcs.c (rcsbuf_open): Use getpagesize() instead of sysconf() for - portability. - (RCS_copydeltas, rcsbuf_fill): Fix -Wall warnings. - -2001-07-04 Derek Price <dprice@collab.net> - - * Makefile.in: Regenerated with new Automake release candidate 1.4h. - -2001-07-03 Derek Price <dprice@collab.net> - - * rcs.c (rcsbuf_open): Reduce memory consumption still further by not - mmapping the entire file when pos is specified. - (rcsbuf_cache_open): Add FIXME comment wrt read-only mmaps and rcsbuf - caching. - -2001-07-03 Derek Price <dprice@collab.net> - - * rcs.c (rcsbuf_open): Use mmap when possible to reduce memory - consumption, especially with large (e.g. binary) files. - (rcsbuf_close): Call munmap. - (rcsbuf_getkey): Remove the buffer fill code when using mmap. - (rcsbuf_getrevnum): Ditto. - (rcsbuf_fill): Remove this function when using mmap. - (rcsbuf_cache_open): Mostly don't use this function with mmap. - (RCS_copydeltas): Don't depend on the file pointer with mmap. - - * stamp-h2.in: Regenerated. - -2001-07-03 Derek Price <dprice@collab.net> - - * update.c: Indent compiler directives. - -2001-07-02 Larry Jones <larry.jones@sdrc.com> - - * import.c (update_rcs_file): Use -kb instead of -ko when comparing - binary files. - (Reported by Gyula Faller <gfaller@graphisoft.hu>.) - -2001-06-28 Larry Jones <larry.jones@sdrc.com> - - * checkout.c (checkout): Explicitly initialize all the static options - so that multiple calls work right. Also fix potential memory leaks. - (Reported by Dr. Dieter Maurer <dieter@sz-sb.de>.) - -2001-06-28 Derek Price <dprice@collab.net> - - * Makefile.in: Regenerated with new version of Automake. - -2001-06-28 Larry Jones <larry.jones@sdrc.com> - - * checkout.c (checkout): Set history_name for export as well as - checkout. - (checkout_proc): Use it. - - * checkout.c (safe_location): Add missing argument in error message. - -2001-06-26 Larry Jones <larry.jones@sdrc.com> - - * recurse.c (start_recursion): Use strip_trailing_slashes instead - of doing it by hand. - - * server.c (pserver_authenticate_connection): Don't clear out - descrambled_password until *after* it's (potentially) logged. - (Reported by Eric Hanchrow <offby1@blarg.net>.) - -2001-06-25 Larry Jones <larry.jones@sdrc.com> - - * recurse.c (start_recursion): Deal with at least some of the cases - where trailing slashes cause confusion. - (Reported by Malcolm Fernandes <fernande@redback.com>.) - * sanity.sh (basica, basicb): Tweak existing tests to check this. - -2001-06-22 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (modules5): New tests with -d on command line. - -2001-06-21 Larry Jones <larry.jones@sdrc.com> - - * modules.c (do_module): Use run_module_prog and server_active to - determine when to call server_prog instead of using server_expanding - so that we get the right paths in the replies as long as we take - mwhere into account in addition to where. - (Reported by Pascal Bourguignon <pjb@informatimago.com>.) - * server.c (server_prog): Use protocol pipe instead of buf_to_net. - * sanity.sh (modules5): Remove FIXCVS comment and update to match. - * server.c, server.h: Remove server_expanding since now unused. - -2001-06-21 Larry Jones <larry.jones@sdrc.com> - for Stephen Rasku <stephen@tgivan.com> - - * admin.c: Corrected spelling mistakes in help. - -2001-06-20 Derek Price <dprice@collab.net> - - * client.c (socket_buffer_shutdown): Fix untested typos. - (Reported by "Jerzy Kaczorowski" <jerzyk@wndtabs.com>.) - - * buffer.c (stdio_buffer_shutdown): Put the call to SHUTDOWN_SERVER in - the correct place. - -2001-06-20 Derek Price <dprice@collab.net> - - * logmsg.c (do_editor): Abort in the case that the file has only - comment lines. - (Original patch from Mark Valentine <mark@thuvia.demon.co.uk>.) - - * logmsg.c (do_editor): Fix rare memory leak. - * sanity.sh (editor): Add tests for aborted log messages. - -2001-06-20 Larry Jones <larry.jones@sdrc.com> - - * server.c (switch_to_user): Only set $CVS_USER if - AUTH_SERVER_SUPPORT is defined. - (Reported by Nalin Dahyabhai <nalin@blade.devel.redhat.com>.) - -2001-06-13 Derek Price <dprice@collab.net> - - * client.c: Fix incorrect fixed-size buffer usage in - connect_to_gserver(). - (Minor changes to a patch from Alexey Mahotkin <alexm@hsys.msk.ru>.) - -2001-06-11 Derek Price <dprice@collab.net> - - * main.c (main): Always print $CVSROOT when parse_cvsroot fails. - * root.c (parse_cvsroot): Tidy error messages and provide more - consistent behavior. - * sanity.sh (crerepos): Adapt to new error messages. - (Suggested by Alexey Mahotkin <alexm@hsys.msk.ru>.) - -2001-06-08 Derek Price <dprice@collab.net> - - * sanity.sh (tagf-28): Use $CVSROOT_DIRNAME. - -2001-06-07 Larry Jones <larry.jones@sdrc.com> - - * rcs.c (RCS_unlock): Reverse kj's change of 1999-10-18: a bare -u - should never break locks, you have to specify a specific revision - to do that. Also add an informative message for a bare -u when - the user doesn't hold any locks. - * commit.c (unlockrcs): Make RCS_unlock quiet, like RCS_lock. - * sanity.sh (rmadd-24): Update to match. - - * sanity.sh (crerepos-6a): Set CVS_RSH for ${testcvs}, not for - dotest_fail. Allow for "broken pipe" rather than "end of file". - -2001-06-07 Derek Price <dprice@collab.net> - - * sanity.sh (tagf): Use $CVSROOT_DIRNAME rather than - /tmp/cvs-sanity/cvsroot. - -2001-06-06 Derek Price <dprice@collab.net> - - (Reformatting, bug fixes, tests, and comments to a - patch from Stephen Cameron <steve.cameron@compaq.com>.) - - * tag.c: (rtag_fileproc, rtag_delete, tag_fileproc) - Changed behavior of "cvs tag -F", "cvs tag -d", "cvs rtag -F" - and "cvs rtag -d" so that they will not disturb existing - branch tags unless a new "-B" option is given. - * sanity.sh (tagf-16 - tagf-33): Added tests for new -B option - to "cvs tag" and "cvs rtag" - -2001-06-06 Derek Price <dprice@collab.net> - - * sanity.sh (crerepos-6a): Set CVS_RSH=false and only for the actual - test call at Larry's suggestion. Also, test the error message since - it's fixed now. - -2001-06-05 Larry Jones <larry.jones@sdrc.com> - - * rcs.c (RCS_unlock): Note when breaking someone else's lock. - (Reported by MURVAI-BUZOGANY Laszlo - <Laszlo.MURVAI-BUZOGANY@gt-systems.hu>.) - * sanity.sh (reserved-14): Update to match. - -2001-06-05 Derek Price <dprice@collab.net> - - * sanity.sh (crerepos-6a): Set CVS_RSH=/bin/false... this is a local - mode only test anyhow. - (Thanks to Larry Jones and Morgan Burke <morgan@sitka.triumf.ca>.) - -2001-05-31 Derek Price <dprice@collab.net> - - * sanity.sh (rcs2-7): Add today to the list of failure dates for rcs2-7 - in the hopes that the data will eventually prove useful to someone - motivated enough to fix the problem. - -2001-05-30 Derek Price <dprice@collab.net> - - * stamp-h2.in: Regenerated. - -2001-05-30 Derek Price <dprice@collab.net> - - * *: Various bug fixes and comments for the following - patch from Donald Sharp <sharpd@cisco.com>: - - * checkout.c (safe_location): cvs co -d <directory> still had - failure modes from the way the -d option works. - * sanity.sh: Misc error message resynching. - -2001-05-29 Derek Price <dprice@collab.net> - - * Makefile.am (cvs_SOURCES): Add root.h. - - * Makefile.in: Regenerated. - * stamp-h2.in: Regenerated. - -2001-05-29 Derek Price <dprice@collab.net> - - * checkout.c (safe_location): Correct formatting. - -2001-05-29 Derek Price <dprice@collab.net> - - * root.c (parse_cvsroot): Fix a comment. - -2001-05-26 Larry Jones <larry.jones@sdrc.com> - - * checkout.c (safe_location): Use old-style definition to keep - non-ANSI compilers happy. - - * sanity.sh (check_respository): Use ${CVSROOT_DIRNAME} instead - of /tmp/cvs-sanity/cvsroot. - -2001-05-25 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (modules5): Add sleep to script to help avoid out of - order messages. - - * filesubr.c (mkdir_if_needed): Return 1 if the directory exists - reguardless of what errno is set to. - (Reported by "Robinson, Greg" <greg.robinson@dsto.defence.gov.au>.) - -2001-05-25 Derek Price <dprice@collab.net> - for Donald Sharp <sharpd@cisco.com> - - * checkout.c: Modified safe_location() to refuse checkout if - the -d option to co specifies inside of the repository. - * import.c: New parameter to safe_location needed to be added. - * cvs.h: New parameter to safe_location needed to be added. - * sanity.sh: Test case to test for failure mode. - -2001-05-23 Larry Jones <larry.jones@sdrc.com> - - * checkout.c (checkout_proc): Don't build top_level_admin directory - when exporting. - (Reported by Tony Byrne <tonyb@directski.com>.) - -2001-05-21 Derek Price <dprice@collab.net> - - * client.c: Fix a mispelling in a comment. - (Patch from Alexey Mahotkin <alexm@hsys.msk.ru>). - -2001-05-05 Larry Jones <larry.jones@sdrc.com> - - * login.c (password_entry_operation): Only warn if unable to open - .cvspass for reading: may be initial login and it doesn't exist yet. - -2001-05-15 Derek Price <dprice@collab.net> - - * client.c (start_tcp_server): Use the struct sockaddr_in declared in - the function. - (Reported by Emil Isberg <isberg@dynarc.se>.) - -2001-05-05 Larry Jones <larry.jones@sdrc.com> - - * annotate.c (annotate): Pass local to do_module and rannotate_proc - so that -l actually works. - * log.c (cvslog): Ditto. - * patch.c (patch): Ditto; make local local instead of global. - (patch_proc): Use local_specified parameter instead of global. - * tag.c (cvstag, rtag_proc): Ditto. - -2001-05-05 Larry Jones <larry.jones@sdrc.com> - - * client.h: Declare "struct buffer" outside prototype for __STDC__ - compilers. - -2001-05-04 Derek Price <dprice@collab.net> - - * client.c: General refactoring. Removed several global variables in - favor of passing locals and/or dynamic evaluation. - (recv_line): Removed this function. - (make_bufs_from_fds): New function with factored code. - (connect_to_forked_server): New prototype. Use new functions. - (connect_to_pserver): New prototype. Use new functions. - (connect_to_gserver): New prototype. Use new API. - (auth_server): Factored this portion of the pserver code so it can be - shared. Rewrote to use buffers rather than depending on a socket. - (start_rsh_server): New prototype. Use new API. - (start_tcp_server): New prototype. Use new API. - (start_server): Factor some code. Use new API. - * client.h: New prototypes. - * cvs.h: Gratuitous reformatting. Use new root.h. - * login.c (login): Use new connect_to_pserver API. - * root.h: New file. Contains some code that used to be in cvs.h. - -2001-05-04 Derek Price <dprice@collab.net> - - * client.c: Gratuitous reformatting. - * client.h: Ditto. - -2001-05-04 Derek Price <dprice@collab.net> - - * zlib.c (compress_buffer_shutdown_input): Use new buffer shutdown - prototype. - (compress_buffer_shutdown_output): Ditto. - (Thanks to Pavel Roskin <proski@gnu.org>.) - -2001-05-03 Derek Price <dprice@collab.net> - - * buffer.c (struct stdio_buffer_closure): New structure to hold a - FILE * and the child's PID when necessary. - (stdio_buffer_initialize): Change proto to accept PID. Set up new - closure. Pass new stdio_buffer_shutdown to buf_initialize. - (stdio_buffer_input): Use new closure. - (stdio_buffer_output): Ditto. - (stdio_buffer_flush): Ditto. - (stdio_buffer_shutdown): New function. Teach buffer to close itself. - (packetizing_buffer_shutdown): Use new buffer shutdown proto. - * buffer.h (struct buffer): New buffer shutdown proto. - (stdio_buffer_initialize): New proto. - * client.c (log_buffer_shutdown): Use new proto. - (socket_buffer_initialize): Pass shutdown func. - (socket_buffer_shutdown): New function. - * server.c (get_responses_and_close): Remove most of the guts. Rely - on the buffer shutdown function from now on. - (start_rsh_server): Return child PID. - -2001-05-03 Larry Jones <larry.jones@sdrc.com> - - * history.c (history_write): Handle the case where the user's home - directory doesn't exist gracefully instead of erroring out. - (Reported by David Hoover <dhoover@cadence.com>.) - -2001-05-03 Derek Price <dprice@collab.net> - - * cvs.h: s/allocate_and_strcat/xrealloc_and_strcat/ since that is what - I wrote in the ChangeLog, oh, so long ago. - * diff.c (diff): Ditto. - * subr.c (allocate_and_strcat, xrealloc_and_strcat): Ditto. - -2001-05-02 Larry Jones <larry.jones@sdrc.com> - - * rcs.c (RCS_getdate): Handle the (unusual!) case where we - can't find any revisions at all. - (Reported by Ryan Grow <rgrow@Dbdoctor.net>.) - -2001-04-30 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (multiroot2-9a): Rename (from multiroot2-9) to avoid - duplicate names; fix to work without SERVER_SUPPORT defined. - (Reported by Pavel Roskin <proski@gnu.org>.) - -2001-04-29 Derek Price <dprice@collab.net> - - * Makefile.am (check-local): Make dependent on localcheck and - remotecheck and move old check target... - (localcheck): here. - - * Makefile.in: Regenerated. - -2001-04-27 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (pserver): Add tests for readers and writers. - -2001-04-27 Derek Price <dprice@collab.net> - - * sanity.sh (version-2r): Update to handle patch releases in version - numbers. - -2001-04-27 Derek Price <dprice@collab.net> - - * version.c: Regenerated. - -2001-04-27 Derek Price <dprice@collab.net> - - * version.c: Regenerated. - -2001-04-27 Larry Jones <larry.jones@sdrc.com> - - * main.c (lookup_command_attribute): Lookup specified command, not - whatever's in the global command_name. - -2001-04-25 Derek Price <dprice@collab.net> - - * Makefile.in: Regenerated using AM 1.4e as of today at 18:10 -0400. - * version.c: Regenerated. - -2001-04-22 Larry Jones <larry.jones@sdrc.com> - - * tag.c (tag_check_valid): Make an unwritable val-tags file a - warning instead of a fatal error. - -2001-04-20 Larry Jones <larry.jones@sdrc.com> - - * annotate.c (annotate_usage): -r and -D are not mutually exclusive. - * main.c (cmd_usage): Add missing version subcommand. - * update.c (update_usage): Add missing -C option. - - * sanity.sh (death2): New tests for previous change. - - * classify.c (Classify_File): Treat a dead revision like the RCS - file doesn't exist. - * sanity.sh: Update to match. - -2001-04-16 Larry Jones <larry.jones@sdrc.com> - - * checkout.c, update.c: Fix usage messages: -r and -D are not - mutually exclusive. - (Suggested by David L. Martin <dlmart2@home.com>.) - - * logmsg.c (do_editor): Don't add a blank line to the message. - * sanity.sh (editor-log-file*): Update to match. - - * checkout.c, update.c: Note in usage message that -k is sticky. - - * server.c: (server_cleanup, wait_sig): Remove ancient SunOS kludge. - (Suggested by Rob Saccoccio <robs@chelsea.net>.) - -2001-04-04 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (dotest, dotest_lit, dotest_fail, dotest_status, - dotest_sort): Don't count on $? being set in then or else clauses. - - * ignore.c (ignore_files): Collect unignored files into a list and - sort it before calling PROC to avoid order dependencies. Rewrite - the while loop to allow normal continues instead of goto. - -2001-04-04 Derek Price <dprice@collab.net> - - * sanity.sh (ignore-on-branch-3): Fix in the remote case. - -2001-04-03 Larry Jones <larry.jones@sdrc.com> - - * update.c (update_fileproc): Remove unused variable (resurrecting). - -2001-04-03 Derek Price <dprice@collab.net> - Larry Jones <larry.jones@sdrc.com> - reported by Jakob Bøhm <JB@Danware.dk> - - * update.c (update_fileproc): Don't store a file with T_UNKNOWN status - in ignlist if present in the sandbox. - * sanity.sh (ignore-on-branch): New test. - (ignore): Tidy this test. - -2001-04-02 Derek Price <dprice@collab.net> - - * sanity.sh: Make sure the test for `id' fails when a nonstandard `id' - is used and the user is root. Fix some quoting in error messages. - (fork): Take `cvs' out of the PATH. - (TODO): Add note about the test suite not working with user names over - eight characters in length. - -2001-04-02 Derek Price <dprice@collab.net> - - * sanity.sh (fork): New test for CVS_SERVER default. - (TODO): Note about eventually removing most of the references to - CVS_SERVER. - -2001-04-02 Larry Jones <larry.jones@sdrc.com> - - * client.c (connect_to_forked_server): Use program_path as the default - server instead of "cvs". - -2001-04-02 Derek Price <dprice@collab.net> - - * sanity.sh: Use less obfuscated English in my comment about sanity - checking sanity.sh. - -2001-04-02 Derek Price <dprice@collab.net> - - * sanity.sh (rm-update-message): Create a test directory again but - change back to the correct directory upon completion this time. - -2001-04-02 Derek Price <dprice@collab.net> - - * sanity.sh: Change last two '[.*]'s to 'test's for - consistency and remove... - (TODO): the note from the TODO list. - -2001-04-02 Derek Price <dprice@collab.net> - - * sanity.sh: Add test for PWD before successful exit. - -2001-03-30 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (rm-update-message): Remove duplicate code. - -2001-03-30 Derek Price <dprice@collab.net> - - * sanity.sh (rm-update-message): New test for local/client-server - warning message discrepency. - -2001-03-30 Larry Jones <larry.jones@sdrc.com> - - * annotate.c: Move annotate() here from rcs.c, support rannotate. - * Makefile.am, Makefile.in: Add annotate.c. - * main.c (cmds[], cmd_usage[]): Add rannotate. - * rcs.c: Move declarations of rcs_delta_op and RCS_deltas to... - * rcs.h: ... here. - * server.c (serve_rannotate): New. - (requests[]): Add rannotate. - * sanity.sh (ann): New tests for rannotate. - - * log.c (rlog_proc): Remove dead code. - -2001-03-30 Derek Price <dprice@collab.net> - - * sanity.sh (join-readonly-conflict): Run more of this through dotest. - -2001-03-30 Larry Jones <larry.jones@sdrc.com> - - * log.c (log_fileproc): Don't output working file for rlog. - * sanity.sh (log): New tests for rlog. - - * cvs.h (mtype): Add MISC type. - * log.c (cvslog): Support rlog as well as log. - (rlog_proc): New. - * main.c (cmds[], cmd_usage[]): Add rlog. - (main): Remove old rlog warning message. - * server.c (serve_rlog): New. - (requests[]): Add rlog. - -2001-03-29 Derek Price <dprice@collab.net> - - * sanity.sh: cd to $TESTDIR once after it is normalized. Make TODO - on history and symlinks more specific. Tested properly this time. - -2001-03-29 Larry Jones <larry.jones@sdrc.com> - - * main.c (cmds[], lookup_command_attribute, main): Include the - command attributes in the global command table instead of inferring - them from the command names. Change the sense of the - CVS_CMD_IGNORE_ADMROOT attribute to match its name. - -2001-03-29 Derek Price <dprice@collab.net> - - * sanity.sh (*, basic2-64): Remove references to TMPPWD. Fix FIXME - at end of script now that $TESTDIR can't be relative. - -2001-03-29 Derek Price <dprice@collab.net> - - * sanity.sh: Normalize TESTDIR even when the user set it. - -2001-03-29 Larry Jones <larry.jones@sdrc.com> - - * client.c (connect_to_pserver, start_tcp_server): Add IP address - to connect failed message. - (connect_to_forked_server, connect_to_pserver, start_tcp_server): Add - trace messages ala start_rsh_server. - (start_rsh_server): Include entire command in trace message for - START_RSH_WITH_POPEN_RW like ! START_RSH_WITH_POPEN_RW does. - -2001-03-29 Derek Price <dprice@collab.net> - - * sanity.sh: Global search & replace ${TESTDIR}/cvsroot with - ${CVSROOT_DIRNAME} for consistency. - -2001-03-29 Derek Price <dprice@collab.net> - - * sanity.sh (conflicts-12[68].5): Remove sanity hack which has allowed - for a CVS bug since May 96/97. Not sure when the bug went bye-bye, but - the tests broke when $TESTDIR != $TMPPWD. - -2001-03-26 Larry Jones <larry.jones@sdrc.com> - - * classify.c (Classify_File): Don't report a conflict for a removed - file when piping. Also simplify the code structure. - (Reported by Milos Kleint <milos.kleint@netbeans.com>.) - * sanity.sh (rmadd2-14[abc]): New tests for above. - -2001-03-24 Noel Cragg <noel@shave.cnet.com> - - * diff.c: mods to allow `-T' and `-y' options to be passed through - to the diff library. This wasn't allowed earlier because of a - similarly named options that got passed through to the old rcs - programs. We've long since stopped sending `-T' to any rcs - utility and have never used `-y'. Any users of moldly CVS - versions which used to support `-T' have (hopefully) upgraded to - one where that option isn't supported. It seems reasonable to - enable them again and pass them through. (sanity.sh still works - anyways...) - (longopts): add short option equivalents for --initial-tab and - --side-by-side. - (diff): add new short options to getopt string and switch - statement. - -2001-03-22 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh: Add check for ${DOTSTAR} with large matches. - -2001-03-23 Derek Price <dprice@collab.net> - - * sanity.sh: Do the same as below for $keep. - -2001-03-23 Derek Price <dprice@collab.net> - - * sanity.sh: Replace 'remote=(yes|no)' with 'remote=(:|false)' since - often 'false' and more often ':' are shell builtins. This makes the - succinct, 'if $remote; then' faster than 'if test $remote = yes; then'. - Alter tests in the rest of the script to match the new usage. Added - a suffix of 'r' to remote test names when it was appropriate and I - remembered. Some reformatting. - -2001-03-22 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (diffmerge1_yours, diffmerge1_mine): Check for exact - output instead of using wildcards to avoid buffer overflows in some - versions of expr. - -2001-03-21 Derek Price <dprice@collab.net> - - * sanity.sh: cd to '/tmp' again rather than $HOME since HOME was set to - a value inside ${TESTDIR} by the script. - -2001-03-20 Derek Price <dprice@collab.net> - - * sanity.sh (diffmerge1): Minor formatting and syntax changes. - - for Jacob Burckhardt <bjacob@ca.metsci.com> - - * sanity.sh (diffmerge1): More merging behavior tests. Specifically, - test some cases which broke before in Karl Tomlinson's diff fix was - checked in today. - -2001-03-20 Derek Price <dprice@collab.net> - - * sanity.sh: Don't use unescaped parens in sh outside of quotes. - -2001-03-20 Derek Price <dprice@collab.net> - - * sanity.sh: Don't remove ${TESTDIR} when -k (keep) set. - -2001-03-20 Derek Price <dprice@collab.net> - - * sanity.sh: Change usage to match the new getopts format and comment. - -2001-03-16 Derek Price <dprice@collab.net> - - * sanity.sh (modules2-nestedrename): New test. Verifies behavior of - renames nested under an ampersand module. - (modules2-ampertag): New test. Verifies an error condition which - prevents some ampersand modules from being checked out when a tag - is specified. - -2001-03-16 Derek Price <dprice@collab.net> - - * sanity.sh (modules2): Additional test for ampersand module behavior - with '-d'. - - for Greg Klanderman <greg@itasoftware.com> - - * checkout.c (build_one_dir): Fix typo where clauses of two - conditionals were reversed in call to Create_Admin. This caused - the CVS/Tag file to be removed in cases where it should have been - set, and vice-versa. It only surfaced in rare cases as this code - is only invoked when using the -d option to build the path to - check out in. Further, the bug would only matter when checking - out a module containing ampersand modules within it, via - client/server CVS. - -2001-03-16 Derek Price <dprice@collab.net> - - * sanity.sh (admin-28-5): Confirm that a missing tag during an - 'admin -n' operation is not a fatal error. - -2001-03-16 Derek Price <dprice@collab.net> - - * admin.c (admin_data): Remove 'quiet' member. - (admin_fileproc): Use global 'really_quiet' rather than - admin_data->quiet. - -2001-03-16 Derek Price <dprice@collab.net> - - * sanity.sh (admin): Replace hardcoded testdir path with the variable. - -2001-03-15 Derek Price <derek.price@openavenue.com> - - * sanity.sh (basica, binfiles, head, admin): Adjust for new messages. - * admin.c (admin_fileproc): Only print messages when not in - really_quiet mode. - - for Stephen Rasku <stephen@tgivan.com> - - * rcs.c (RCS_tag2rev): Make a missing tag a survivable error. - -2001-03-15 Larry Jones <larry.jones@sdrc.com> - - * subr.c (sleep_past): Fix various bugs that would result in a - negative sleep time if it weren't unsigned; since it is, it would - result in a very large sleep time. Ensure that us is always less - than 1000000. Don't try to sleep for more 1 sec with usleep. - Cast NULL select arguments to correct type just in case. - -2001-03-14 Derek Price <derek.price@openavenue.com> - - * subr.c (sleep_past): New function. - * client.c (get_responses_and_close): Use new function. - * commit.c (commit): Ditto. - * update.c (do_update): Ditto. - * cvs.h: Prototype new function. - - * stamp-h2.in: Regenerated. - -2001-03-14 Derek Price <derek.price@openavenue.com> - - * Makefile.in: Regenerated. - * stamp-h2.in: Ditto. - -2001-03-14 Larry Jones <larry.jones@sdrc.com> - - * commit.c (check_fileproc): Allow adding on the trunk when there's - an existing non-Attic RCS file as long as the head revision is dead. - This can happen due to an aborted resurrection. - (commit_fileproc): When resurrecting, consider the dead revision - along with the other files' revisions. - (findmaxrev): Avoid unnecessary work. - (checkaddfile): Only warn if file isn't in Attic as expected. - (Reported by Ross Burton <r.burton@180sw.com>.) - * sanity.sh (basica-r*): New tests for above. - (basica-o4): Update to match. - -2001-03-09 Larry Jones <larry.jones@sdrc.com> - - * edit.c (edit_fileproc, unedit_fileproc): Some implementations of - asctime/ctime apparently use a leading zero on the date instead - of the space required by the C Standard. Correct for this so that - shared working directories work without hassle. - (Reported by David L. Martin <dlmart2@home.com>.) - * entries.c (fgetentent): Ditto. - * vers_ts.c (time_stamp_server, time_stamp) Ditto. - -2001-03-07 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (basica, binfiles2, head, admin): Update to match - change to admin.c. - -2001-03-06 Larry Jones <larry.jones@sdrc.com> - - * client.c (recv_bytes): Handle EOF as in recv_line(). - (Reported by Pavel Roskin <proski@gnu.org>.) - - * admin.c (admin_fileproc): Change final error message to clarify - that CVS refused to modify the RCS file rather than being unable to. - -2001-02-28 Jim Meyering <meyering@lucent.com> - - * commit.c (commit_usage): Use `-F logfile' (rather than -F file') in - the description of that option, to be consistent with the `-F logfile' - in the Usage: line. Use spaces instead of TAB characters, and realign. - -2001-03-02 Derek Price <derek.price@openavenue.com> - - * sanity.sh (crerepos): Make failed ${CVS_RSH-rsh} attempt print the - name of the command it actually used rather than 'rsh'. - -2001-02-27 Derek Price <derek.price@openavenue.com> - - * sanity.sh (modules2-ampermod-*): Added these tests to make sure the - top level directory is created in an ampermodule when '-n' is passed to - checkout. - - original bug report from - Wolfgang Haefelinger <Wolfgang.Haefelinger@Dresdner-Bank.com> - -2001-02-27 Derek Price <derek.price@openavenue.com> - - * sanity.sh (version-[12]): replace ' (client/server)' with .* in these - two tests so that 'make check' works with whatever client/server - options the executable was compiled with. - -2001-02-23 Derek Price <derek.price@openavenue.com> - - * main.c (main): Only check a cvsroot_t's isremote member when client - support is enabled. - * server.c: Include GSSAPI headers with client support as well as - server support. - -2001-02-21 Larry Jones <larry.jones@sdrc.com> - - * modules.c, cvs.h (do_module): Add build_dirs argument and use it - instead of run_module_prog. Change all callers. - * tag.c (cvstag): For rtag, don't build directories. - * sanity.sh (modules3): Update to match. - -2001-02-20 Derek Price <derek.price@openavenue.com> - - * client.c: Use xgssapi.h. - * server.c: Ditto. - -2001-02-15 Derek Price <derek.price@openavenue.com> - - * Makefile.am (cvs_SOURCES): Correct error from yesterday. - * Makefile.in: Regenerated. - -2001-02-14 Derek Price <derek.price@openavenue.com> - - * server.c: Include xselect.h. - * update.c (do_update): Use best available sleep function. - -2001-02-14 Derek Price <derek.price@openavenue.com> - - * Makefile.am (cvs_SOURCES): Alphabetize and split to one/line. - (cvs_LDADD): Alphabetize and split to one/line. - * Makefile.in: Regenerated. - -2001-02-14 Larry Jones <larry.jones@sdrc.com> - - * build_src.com: Remove references to rtag.c & rtag.obj. - -2001-02-13 Derek Price <derek.price@openavenue.com> - - * main.c (date_to_tm): New function to convert an RCS date string to a - struct tm. - (tm_to_internet): New function to convert a struct tm to a date string - as specified by RFC822 and amended by RFC 1123. - (date_to_internet): Use the above two functions and a struct tm - intermediary for conversion. - * patch.c (patch_fileproc): Answer somebody's comment and use the new - diff_exec API. - * rcs.c (RCS_checkin): Use new diff_exec API. - (RCS_delete_revs): Use new diff_exec API. - (make_file_label): If the file name is DEVNULL, date it the Epoch for - compatibility with the POSIX.2 spec and Larry Wall's patch - implementation. - * rcscmds.c (diff_exec): Accept new label arguments. - * sanity.sh (death2): Update some diff tests to accept the new format. - * update.c (patch_file): Use new diff_exec API. - * diff.c (diff_fileproc): Create header labels appropriate for - compatibility with the Larry Wall version of patch. - (diff): Rename calls to strcat_and_allocate. - (strcat_and_allocate): Rename and move... - * subr.c (xrealloc_and_strcat): here. - * cvs.h: Update prototypes to match. - -2001-02-13 Derek Price <derek.price@openavenue.com> - - * Makefile.am (cvs_SOURCES): Remove rtag.c. - -2001-02-07 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (directory_cmp): Return status rather than setting ISDIFF. - (basic2): Rewrite using dotest. - -2001-02-06 Larry Jones <larry.jones@sdrc.com> - - * tag.c, rtag.c: Merge with tag.c being the surviving file. - * Makefile.in: Update to match. - * main.c (cmds): rtag() => cvstag(). - * server.c (serve_rtag): Ditto, and set command name. - -2001-02-06 Derek Price <derek.price@openavenue.com> - Rex Jolliff <Rex_Jolliff@notes.ymp.gov> - Shawn Smith <Shawn_Smith@notes.ymp.gov> - - * add.c: Replace opendir, closedir, & readdir calls with CVS_OPENDIR, - CVS_CLOSEDIR, & CVS_READDIR in support of changes to handle VMS DEC C - 5.7 {open,read,close}dir problems. Check today's entry in the vms - subdir for more. - * filesubr.c: ditto - * find_names.c: ditto - * ignore.c: ditto - * import.c: ditto - * lock.c: ditto - * update.c: ditto - -2001-02-02 Larry Jones <larry.jones@sdrc.com> - - * error.h: Changed include guard macro from _error_h_ to ERROR_H; - names beginning with underscore are reserved. - * login.c (password_entry_parseline, password_entry_operation, - password_entry_operation_e, password_entry_operation_t): Removed - leading underscore(s). - (password_entry_parseline): Corrected error messages. - (password_entry_operation): Fixed uninitialized variable (password). - (login): Removed unused variable (found_password). - - * rtag.c (rtag_proc): Call lock_tree_for_write() before calling - start_recursion. This fixes a serious problem where do_recursion - was reading and caching RCS files without any locks in place and - that information was subsequently being used to rewrite the file - causing any intermediate changes to be lost. - (rtag_filesdoneproc): Defunct. - (Reported by Karl Tomlinson <k.tomlinson@auckland.ac.nz>.) - * tag.c (cvstag, tag_filesdoneproc): Ditto. - * lock.c (lock_tree_for_write): Add which argument, change all - callers to pass W_LOCAL. - * rcs.h: Ditto. - -2001-01-29 Derek Price <derek.price@openavenue.com> - - * client.c (get_cvs_port_number): change the prototype to accept a - const cvsroot_t * as input and add a FIXME comment - * cvs.h: new prototypes for get_cvs_port_number & normalize_cvsroot - * login.c (_password_entry_operation): consolidate all the ~/.cvspass - access into a single new function which reads ~/.cvspass in a backwards - compatible manner - (logout): use the new _password_entry_operation function - (login): ditto - (get_cvs_password): ditto - * root.c (normalize_cvsroot): move knowledge of default port & username - values inside - -2001-01-29 Larry Jones <larry.jones@sdrc.com> - - * subr.c (shell_escape): New function. - * cvs.h: Declare it. - * logmsg.c (logfile_write): Use it to avoid problems with filenames - containing "'". - (Reported by Gerhard Ahuis <gerhard@ats.xs4all.nl>.) - - * server.c (outbuf_memory_error, pserver_authenticate_connection, - kserver_authenticate_connection): If available, use syslog() to - record some errors. - -2001-01-25 Larry Jones <larry.jones@sdrc.com> - - * server.c (do_cvs_command): If there's a partial output line left - over and the client doesn't support MT, go ahead and send it in an - M response instead of just dropping it. - (Reported by Milos Kleint <Milos.Kleint@netbeans.com>.) - - * update.c (update_fileproc): Handle toss_local_changes in the - T_NEEDS_MERGE case. - (Inspired by Noel L Yap <yap_noel@jpmorgan.com>.) - * sanity.sh (clean): New tests for above. - -2001-01-23 Derek Price <derek.price@openavenue.com> - - * run.c (run_exec): flush, if used, stderr and stdout before exit - * server.c (cvs_flusherr): flush stderr & send a stderr flush command - on the protocol pipe - (cvs_flushout): like above, for stdout - (do_cvs_command): handle flushes properly - * sanity.sh (reserved): make the commitinfo script echo errors to - stderr rather than stdin - -2001-01-18 Larry Jones <larry.jones@sdrc.com> - - * log.c (option_revlist, revlist, log_usage, cvslog, - log_parse_revlist, log_expand_revlist, log_version_requested): Add - support for :: for exclusive ranges. - * admin.c (admin_usage): Reorder -o to be parallel to log -r. - * sanity.sh (log): New tests for above. - -2001-01-18 Derek Price <derek.price@openavenue.com> - - * main.c: Add '2001' to the range of copyright years listed by the - --version option - * version.c.in (version): check current_parsed_root before its isremote - member to avoid a core dump - * sanity.sh (version): add a test for the version command - - * version.c: regenerated - -2001-01-12 Larry Jones <larry.jones@sdrc.com> - - * rcs.c, rcs.h (RCS_lock, RCS_unlock): Use RCS_gettag to find the - correct revision so that symbolic tags work correctly. (This - requires removing the "const" from the rev parameter since it's - passed to RCS_gettag which might modify it.) - (Reported by irina sturm <irina.sturm@st.com>.) - -2001-01-11 Larry Jones <larry.jones@sdrc.com> - - * run.c (close_on_exec): Remove check for FD_CLOEXEC. As far as I - can see, it's *never* been defined, which defeats the whole point. - If F_SETFD is defined, it's probably safe to use it. - - * server.c (do_cvs_command): Call close_on_exec on the protocol and - flow control pipes in the child process so they don't get inherited - by any subsidiary processes. - (Reported by Tristan Gingold <tgi@netgem.com>.) - - * cvs.h (free_cvsroot_t): Spell correctly (was free_CVSroot_t). - -2001-01-10 Derek Price <derek.price@openavenue.com> - Rex Jolliff <Rex_Jolliff@notes.ymp.gov> - - * build_src.com: VMS changes - * filesubr.c: replace calls to unlink() with CVS_UNLINK() for VMS - * rcs.c: ditto - -2001-01-10 Derek Price <derek.price@openavenue.com> - - * main.c (current_root): explicitly list this as a static global - -2001-01-10 Derek Price <derek.price@openavenue.com> - - * cvs.h (get_cvs_port_number): change name & prototype from - get_port_number - * client.c (get_cvs_port_number): new function which returns a port - number based on a cvsroot_t rather than requiring all possible sources - passed in - (connect_to_pserver): use new get_cvs_port_number function - (connect_to_server): ditto - * login.c (get_password): use new get_cvs_port_number function - (login): ditto - (logout): ditto - -2001-01-10 Derek Price <derek.price@openavenue.com> - - * Makefile.am ($(srcdir)/version.c): specify $(srcdir) for all subparts - of the build since some systems don't allow mv's across partitions - * Makefile.in: regenerated - -2001-01-10 Derek Price <derek.price@openavenue.com> - - * Makefile.am (version.c): specify $(srcdir) explicitly in target rule - so version.c gets built properly for all makes. - (version.o): specify $(srcdir)/version.c explicitly so dependency is - found and built properly - * Makefile.in: regenerated - -2001-01-09 Derek Price <derek.price@openavenue.com> - - * version.c: updated timestamp - -2001-01-09 Larry Jones <larry.jones@sdrc.com> - - * server.c (server): Change to server_temp_dir immediately after - creating it so that any stray files that happen to be created go - there instead of in the server's initial directory, wherever that - may be. - * sanity.sh (modules5-15): Update to match. - - * version.c.in: Update to match Derek's change to version.c. - -2001-01-09 Derek Price <derek.price@openavenue.com> - - * cvs.h: Remove the various CVSroot_* bits and replace them with a - single structure of type cvsroot_t (current_parsed_root) - - * root.c (parse_cvsroot): return pointer to a new cvsroot_t rather than - altering global variables - (local_cvsroot): return a pointer to a new cvsroot_t rather than - setting globals. changed the name of this function from - set_local_cvsroot to better explain new functionality - (new_cvsroot_t): new initializer function - (free_cvsroot_t): new function - (others): use current_parsed_root rather than the old CVSroot_* globals - - * add.c: use current_parsed_root rather than the old CVSroot_* globals - * admin.c: ditto - * checkout.c: ditto - * client.c: ditto - * commit.c: ditto - * create_adm.c: ditto - * diff.c: ditto - * edit.c: ditto - * expand_path.c: ditto - * find_names.c: ditto - * history.c: ditto - * ignore.c: ditto - * import.c: ditto - * lock.c: ditto - * log.c: ditto - * login.c: ditto - * logmsg.c: ditto - * main.c: ditto - * mkmodules.c: ditto - * modules.c: ditto - * parseinfo.c: ditto - * patch.c: ditto - * rcs.c: ditto - * recurse.c: ditto - * release.c: ditto - * remove.c: ditto - * repos.c: ditto - * rtag.c: ditto - * server.c: ditto - * status.c: ditto - * tag.c: ditto - * update.c: ditto - * version.c: ditto - * watch.c: ditto - * wrapper.c: ditto - -2001-01-05 Derek Price <derek.price@openavenue.com> - - * cvs.h (enum CVSmethod): add null_method - * root.c (method_names): correlate null_method & "undefined" - (parse_cvsroot): make two error cases non fatal - * sanity.sh (crerepos-6b): account for new error message, re above - -2001-01-05 Derek Price <derek.price@openavenue.com> - - * src/Makefile.am (cvsbug, cvsbug_EXTRA_DIST, EXTRA_DIST): move cvsbug - target to configure.in - see ../ChangeLog for more - * src/cvsbug.in: Rename from cvsbug.sh - * src/cvsbug.sh: Rename to cvsbug.in - -2001-01-04 Larry Jones <larry.jones@sdrc.com> - - * Makefile.am (cvsbug): Explicitly list input file ($< is only - valid in inference rules). - * Makefile.in: Ditto. - -2001-01-04 Derek Price <derek.price@openavenue.com> - - * sanity.sh: use getopts rather than getopt for portability reasons - -2001-01-03 Derek Price <derek.price@openavenue.com> - - * Makefile.am (remotecheck): depend on 'all' - * Makefile.in: regenerated - -2000-12-29 Derek Price <derek.price@openavenue.com> - - * sanity.sh: remove explicit "$@" from last checkin and move the 'do' - to the line following the 'for'. Apparently this is more portable. - -2000-12-29 Derek Price <derek.price@openavenue.com> - - * sanity.sh: make "$@" explicit in 'for' statement since Solaris 5.6's - implementation of Bourne shell doesn't seem to implement this default - behavior. - -2000-12-27 Derek Price <derek.price@openavenue.com> - - * sanity.sh: add a -f option for continuing from a particular test - and shorten --keep to -k so we can use the getopt function. - -2000-12-27 Derek Price <derek.price@openavenue.com> - - * Makefile.am (remotecheck): Make remotecheck dependant on all - * Makefile.in: regenerated - -2000-12-26 Derek Price <derek.price@openavenue.com> - - * Makefile.in: update timestamp - * stamp-h2.in: ditto - * version.c: ditto - -2000-12-26 Derek Price <derek.price@openavenue.com> - - * Makefile.am: new target for version.c - (EXTRA_DIST): add version.c.in & version.c so builds work when - configure doesn't - * Makefile.in: Regenerated - * stamp-h2.in: update timestamp - * version.c: ditto - -2000-12-26 Derek Price <derek.price@openavenue.com> - - * Makefile.am (INCLUDES): add zlib - * Makefile.in: Regenerated - -2000-12-22 Derek Price <derek.price@openavenue.com> - - * Makefile.am (DISTCLEANFILES): added a few files - (INCLUDES): commented - * Makefile.in: Regenerated - -2000-12-21 Derek Price <derek.price@openavenue.com> - - * .cvsignore: Added .deps directory and a new stamp file - * Makefile.am: New file needed by Automake - * Makefile.in: Regenerated - * stamp-h2.in: New stamp file created by Automake - * version.c.in: use configure to generate version.c - -2000-12-16 Derek Price <derek.price@openavenue.com> - - * server.c (server_update): Keep the vers structure up to date after - sending a Remove or Remove-entry command to the client - * update.c (update): remove call to server_updated() after - scratch_file() - (scratch_file): in server mode, call server_updated(), otherwise keep - the vers structure up to date - (join_file): add a trace, save the revision to Register() on a remove - before calling server_scratch & server_updated - * sanity.sh (join): Add test for a remove/add caused by an update - to a new branch and a join in the same step. - -2000-12-15 Larry Jones <larry.jones@sdrc.com> - - * error.c (error): Add %ld and %lu. - - * history.c: Change hrec.idx from int to long, reformat NEXT_BAR - for readability, add hrec_idx. - (fill_hrec): Change initialization to be portable and always set - idx so it can be used as a line number in error messages; improve - parsing and error checking. - (read_hrecs): Initialize hrec_idx, handle embedded NULs, warn about - no newline at end of file. - (select_hrec): Add basic validity checking. - -2000-12-07 Larry Jones <larry.jones@sdrc.com> - - * history.c (history): Allow multiple -m options as documented. - -2000-11-29 Derek Price <derek.price@openavenue.com> - - * root.c (parse_cvsroot): back out yesterday's redundant changes - * main.c (main): fix CVSROOT trace message to look like other trace - messages - * sanity.sh (multiroot2-9): expect new trace message - -2000-11-28 Derek Price <derek.price@openavenue.com> - - * root.c (parse_cvsroot): add trace on this function - * client.c (get_port_number): make trace print look like others - -2000-11-16 Derek Price <derek.price@openavenue.com> - - * filesubr.c (cvs_temp_file): back out the previous change in the - interests of portability, add an assertion, and fix the header comment - -2000-11-16 Derek Price <derek.price@openavenue.com> - - * filesubr.c (cvs_temp_file): refine the exit behavior to notice if - the out param was passed in NULL and, if so, avoid setting it and delete - the temp file for later - -2000-11-16 Derek Price <derek.price@openavenue.com> - - * filesubr.c (cvs_temp_file): fixed a garble or two, added some - additional error checking, and added a comment - -2000-11-15 Derek Price <derek.price@openavenue.com> - - * filesubr.c (cvs_temp_file): added cvs_temp_file - function to use mkstemp rather than one of the other temp file - generators as gcc keeps complaining I should. - (cvs_temp_name): altered this function to simply wrap cvs_temp_file - and deprecated it - * cvs.h: added prototype for cvs_temp_file - * commit.c (commit): use the new function instead of the old and plug - an old (though related) memory leak. - * import.c (import): use the new function - * login.c (login): Ditto - * logmsg.c (do_editor, do_verify): Ditto - * patch.c (patch_fileproc): Ditto - -2000-11-14 Larry Jones <larry.jones@sdrc.com> - - * update.c, update.h (do_update): Add xdotemplate parameter. - Change all callers. - (update_dirent_proc): Use dotemplate for Create_Admin, not 1. - * checkout.c (checkout_proc): Don't create CVS/Template if - exporting. - (Reported by Andrey Podkolzin <mdh@zenon.net>.) - -2000-11-08 Larry Jones <larry.jones@sdrc.com> - - * admin.c (admin): Use getgroups() to check for membership in - CVS_ADMIN_GROUP if it exists. In any event, check the user's - primary group in addition to any additional groups. - (Reported by Thomas Okken <TOkken@refco.com>.) - -2000-11-06 Jim Meyering <meyering@lucent.com> - - Compile with gcc's -Wformat and fix the exposed problems. - * root.c (parse_cvsroot) [! HAVE_KERBEROS]: Provide an argument - for the %s error format spec. - [! HAVE_GSSAPI]: Likewise. - (normalize_cvsroot): Put comment delimiters around token after `#endif'. - -2000-11-03 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh: Some versions of sed require a space between -e and - the value. - -2000-10-27 Larry Jones <larry.jones@sdrc.com> - - * checkout.c (checkout): Don't check for a safe location if just - cat'ing the module database. - (Reported by Ilya Martynov <m_ilya@agava.com>.) - Have -s set cat as well as status; it simplifies the code. - -2000-10-26 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (join-admin-2): Check output from all commands instead - of (mostly) discarding. (Some of the tests used to produce stray - output in remote mode.) - - * sanity.sh (dotest_line_by_line): Handle empty lines in pattern - (expr doesn't distingish between successfully matching nothing - and failing to match anything). - - * sanity.sh (dotest_internal): Rearrange and use elif to simplify. - -2000-10-24 Jim Meyering <meyering@lucent.com> - - Fix a bug, introduced with my fix of 2000-07-10, whereby -kk would - sometimes be ignored for some of the files involved in an update. - - * update.c (join_file): Restore the original value of `options' - right after calling checkout_file. - * sanity.sh (join-admin-2): New test for this. - -2000-10-23 Derek Price <derek.price@openavenue.com> - James Youngman <jay@gnu.org> - - * sanity.sh: it's /gnu/bin, not /gun/bin. Thanks go to James Youngman - <jay@gnu.org> for the bug report and patch. - -2000-10-20 Jim Kingdon <http://sourceforge.net/users/kingdon/> - - * server.c (switch_to_user): Set CVS_USER. Patch from Sudish - Joseph and popularized by dozens (e.g. mozilla.org, also others). - -2000-10-20 Derek Price <derek.price@openavenue.com> - KOIE Hidetaka <hide@koie.org> - - * root.c (normalize_cvsroot): plug a memory leak. Thanks to - KOIE Hidetaka <hide@koie.org> - -2000-10-18 Derek Price <derek.price@openavenue.com> - - * client.c (connect_to_pserver): added a close brace the lack of which - was preventing compilation when gssapi was enabled. Removed a - redundant check for HAVE_KERBEROS. - -2000-10-18 Derek Price <derek.price@openavenue.com> - - * root.c (normalize_cvsroot): removed references to free_port_s and the - now useless call to free now that port_s is on the stack. Thanks to - Jon Miner. - -2000-10-18 Derek Price <derek.price@openavenue.com> - - * root.c (normalize_cvsroot): remove calls to snprintf for - compatibility with M$ Windoze. - -2000-10-18 Derek Price <derek.price@openavenue.com> - - * sanity.sh (crerepos-6a, crerepos-6a-r): fix a "?" in a regex & pipe - the output of a test to /dev/null since we don't know what error - messages specific rsh implementations will output. - -2000-10-17 Derek Price <derek.price@openavenue.com> - - * cvs.h: added CVSroot_password variable. Provided prototypes for - get_port_number & normalize_cvsroot. - * client.c (get_port_number): Fixed an ANSI prototype I had included - for get_port_number. - * login.c (login, logout): Removed two checks for a non-null - CVSroot_username since parse_cvsroot now supplies a default in pserver - mode. allow for a password in CVSROOT - (get_cvs_passsword): return CVSroot_password if it was supplied - in the CVSROOT. - * root.c (parse_cvsroot): Changed CVSROOT spec from - :method:user@host/port:/cvsroot to - :method:[[user][:password]@]host[:[port]]/cvsroot - Removed the xstrdup function since we'd rather have the error checking - from the version in subr.c anyhow. Moved some error messages which - looked like they would print the wrong error message after a failed - connect_to_gserver call. - (normalize_cvsroot): return a normalized CVSROOT for use in the - .cvspass file. - * sanity.sh (crerepos-6): fix a test which was expecting an old error - message. - - * client.c (connect_to_pserver): Moved some error messages which looked like they - would print the wrong error message after a failed connect_to_gserver - call. - - * login.c (login): Paranoiacly zero a password in memory. - -2000-10-12 Derek Price <derek.price@openavenue.com> - - * client.c (auth_server_port_number -> get_port_number, start_pserver, - start_tcp_server): use a port specified in CVSROOT instead of the - default port. Failing that, use the CVS_CLIENT_PORT environment - variable. - * cvs.h: Added global CVSroot_port & renamed auth_server_port_number. - * root.c (parse_cvsroot): Parse the new CVSROOT format properly. - Incidentally reformated some error messages for uniformity and - readability. - * sanity.sh (crerepos): fix two tests which were now expecting the - wrong error message. - -2000-10-11 Larry Jones <larry.jones@sdrc.com> - - * server.c (pserver_authenticate_connection): Fix stupid mistake - in previous change. - -2000-10-11 Derek Price <derek.price@openavenue.com> - - * main.c (main): Dispose old CVSroot when parsing a '-d' option if - free_CVSroot is set. - * root.c (parse_cvsroot): remove references to 'cvsroot_parsed', a - static boolean I expect hasn't been used since CVS learned to handle - multiple CVSROOTs. - -2000-10-10 Larry Jones <larry.jones@sdrc.com> - - * server.c (print_error): Make up a message if strerror fails. - - * server.c (pserver_authenticate_connection): Give a real error - message for an invalid repository. - -2000-10-06 Derek Price <derek.price@openavenue.com> - - * add.c (add): Made quiet mode affect some warning messages as seemed - appropriate. Specifically, some of the messages which a user might - want to ignore so they don't have to be quite so specific on the - command line: files added twice, files already in the repository and - check out properly (i.e. but picked up by 'cvs add *'), & files which - are readded in place of a dead revision or onto a branch. '-q' will - not change the non-zero exit code for the cases where at least one - passed in file name was already in the Entries file. There seems to - be a precedent in remove.c. - * remove.c (cvsremove): switched the "use cvs ci to make these changes - permanent message" to only print w/o '-Q' to match the new behavior of - add. This seems appropriate as '-Q' is defined to restrict messages - to critical errors. - * sanity.sh (adderrmsg): Added some tests for the above behavior. - -2000-10-05 Larry Jones <larry.jones@sdrc.com> - - * client.c (call_in_directory): Create CVSADM directory if it doesn't - exist in the directory. This makes client/server work more like - standalone when checking out into an existing (non-CVS) directory. - * sanity.sh (dirs2, conflicts3, toplevel): Update to match. - -2000-10-03 Larry Jones <larry.jones@sdrc.com> - - * filesubr.c (get_homedir): Ignore $HOME when running in server mode. - -2000-10-02 Larry Jones <larry.jones@sdrc.com> - - * cvs.h: Define (and use) T_PATCH as a valid file classification - even when SERVER_SUPPORT isn't defined -- it simplifies the code. - * classify.c (Classify_File): Ditto. - * commit.c (check_fileproc): Ditto. - * status.c (status_fileproc): Ditto. - * update.c (update_fileproc): Ditto. - * tag.c (check_fileproc): Accept T_PATCH in addition to T_CHECKOUT. - * sanity.sh (tagc-10): Update to match. - -2000-09-29 Larry Jones <larry.jones@sdrc.com> - - * client.c (get_responses_and_close): Reset server_fd to -1 after - shutting down. - (Reported by Joerg Thoennes <Joerg.Thoennes@data-sciences.de>.) - -2000-09-27 Larry Jones <larry.jones@sdrc.com> - - * commit.c (commit): Don't sleep before returning in server mode, - just let the client do it. - * update.c (do_update): Ditto. - - * sanity.sh (find_tool): Correct method of checking for GNU tools. - - * checkout.c (checkout_proc): Match up user directories with - repository directories instead of using Emptydir. - * sanity.sh (cvsadm, emptydir): Update to match. - -2000-09-19 Larry Jones <larry.jones@sdrc.com> - - * version.c: Push version number to 1.11.0.1. - - * version.c: Version 1.11. - -2000-09-07 Larry Jones <larry.jones@sdrc.com> - - * Makefile.in: Use @bindir@, @libdir@, @infodir@, and @mandir@ - from autoconf. - -2000-08-23 Larry Jones <larry.jones@sdrc.com> - - * 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 <jkingdon@dhcp-net200-89.su.valinux.com> - - * main.c (lookup_command_attribute): Add "release" to commands - which can be done by a read-only user. - -2000-08-23 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * rcs.c (expand_keywords): Handle the unusual case of log == NULL. - (Reported by Craig Metz <cmetz@inner.net>.) - -2000-08-01 Larry Jones <larry.jones@sdrc.com> - - * subr.c (pathname_levels): Fix bug that miscounts adjacent - slashes. - (Patch submitted by Tanaka Akira <akr@m17n.org>.) - - * loginc.c (login): If available, use getpassphrase instead of - getpass to support long passwords on Solaris. - -2000-07-28 Larry Jones <larry.jones@sdrc.com> - - * server.c (server_noop): Avoid do_cvs_command() overhead. - (requests): Make noop RQ_ROOTLESS. - -2000-07-27 Noel Cragg <noel@red-bean.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <proski@gnu.org> - and Larry Jones <larry.jones@sdrc.com> - - * mkmodules.c (config_contents): Add a commented out example for - LockDir. Don't suggest PreservePermissions unless it's enabled. - -2000-07-17 Larry Jones <larry.jones@sdrc.com> - - * login.c (get_cvs_password): Handle malformed ~/.cvspass more - gracefully. - -2000-07-12 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (modules5): New tests for module programs. - -2000-07-11 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * zlib.c (gunzip_and_write): Fix type clashes. - - * main.c (main): Remove unused variables. - -2000-07-10 Jim Meyering <meyering@lucent.com> - - 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 <larry.jones@sdrc.com> - - * 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 <kfogel@red-bean.com> - - * 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 <larry.jones@sdrc.com> - - 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 <larry.jones@sdrc.com> - - * 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 <kfogel@red-bean.com> - - * 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 <jpmg@eng.cam.ac.uk>.) - - * 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 <larry.jones@sdrc.com> - - * sanity.sh (modules): Rewrite using dotest. Add "modules-" - prefix to test names. - -2000-06-28 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <proski@gnu.org> - and Larry Jones <larry.jones@sdrc.com> - - * server.c (switch_to_user): Only set CVS_Username if - AUTH_SERVER_SUPPORT is defined. - -2000-06-23 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * root.c (parse_cvsroot): Put the terminating NUL byte into the - string *before* copying it, not after. :-( - -2000-06-19 Larry Jones <larry.jones@sdrc.com> - - * main.c (main): Plug memory leaks. - * root.c (parse_cvsroot, set_local_cvsroot): Ditto. - * server.c (serve_root): Ditto. - -2000-06-16 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * checkout.c (checkout_proc): Fix non-ANSI code in call to - findslash(), minor cleanups. - -2000-06-14 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <dietmar.petras@elsa.de>.) - -2000-06-03 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * rcs.c (RCS_checkin, RCS_cmp_file): Plug memory leaks. (Patch - submitted by Chris G. Demetriou <cgd@sibyte.com>.) - -2000-05-20 Ian Lance Taylor <ian@zembu.com> - - * client.c (connect_to_gserver): Handle server error messages - reasonably. - -2000-05-19 Larry Jones <larry.jones@sdrc.com> - - * server.c (requests): Make Global_option RQ_ROOTLESS so it can be - used with init. - -2000-05-18 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <meyering@lucent.com> - - * 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 <kingdon@redhat.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <rhdv@rhdv.cistron.nl>.) - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * server.c: More error messages. - -2000-05-02 Donald Sharp <sharpd@cisco.com> - and Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * server.c (dirswitch): Set pending_error_text in addition to - pending_error to aid in problem determination. - -2000-03-23 Larry Jones <larry.jones@sdrc.com> - - * mkmodules.c (mkmodules): Return without doing anything if noexec - is set to avoid trashing existing files. - -2000-03-23 Larry Jones <larry.jones@sdrc.com> - - * main.c: Alphabetize cmds[] and cmd_usage[] and add server - commands to cmd_usage[]. - -2000-03-21 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (client-1): May get "Broken pipe" message from the - "server" in addition to the expected output. - -2000-03-17 Larry Jones <larry.jones@sdrc.com> - - * server.c (switch_to_user): Set CVS_Username if it hasn't already - been set elsewhere. (Patch submitted by Gordon Matzigkeit - <gord@fig.org>). - -2000-03-13 Larry Jones <larry.jones@sdrc.com> - - * parseinfo.c: Add extern to logHistory declaration. (Reported by - <John.Tytgat@aaug.net>.) - (parse_config): Reformat logHistory code. - -2000-03-10 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * mkmodules.c (init): Use mkdir_if_needed to create CVSROOT/Emptydir - so we don't fail if run multiple times. (Reported by KOIE Hidetaka - <hide@koie.org>.) - * sanity.sh (1a): New test for above. - -2000-03-02 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * import.c (import): Don't allow importing the repository. - * sanity.sh (errmsg2-20, errmsg2-21): New tests for above. - -2000-03-01 Larry Jones <larry.jones@sdrc.com> - - * main.c (main): Update year in copyright message. - -2000-03-01 Larry Jones <larry.jones@sdrc.com> - - * logmsg.c (do_editor): Correct previous change. - -2000-02-29 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * sanity.sh (find_tool): New function to replace duplicated code. - -2000-02-25 Larry Jones <larry.jones@sdrc.com> - - * import.c (add_rcs_file): Don't abort just because lstat fails. - -2000-02-16 Jim Meyering <meyering@lucent.com> - - 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 <kfogel@red-bean.com> - - * 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 <kj@sourcegear.com> - - * 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 <cavanaug@sr.hp.com>) - -2000-02-18 Karl Fogel <kfogel@red-bean.com> - - * 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 <larry.jones@sdrc.com> - - * sanity.sh (perms symlinks symlinks2 hardlinks): Don't run by - default since PreservePermissions code is now disabled. - -2000-02-17 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (import-113): Revise to match Jim Meyering's fix. - -2000-02-16 Larry Jones <larry.jones@sdrc.com> - - * add.c (add): Don't allow adding files or directories to Emptydir. - (Patch submitted by Chris Cameron <chris.cameron@ot.co.nz>.) - * sanity.sh (emptydir): Revise (emptydir-7 and emptydir-8) for this. - -2000-02-16 Jim Meyering <meyering@lucent.com> - - * update.c (join_file): Correct typo in diagnostic: - change `file %s is present...' to `file %s is not present...'. - -2000-02-10 Larry Jones <larry.jones@sdrc.com> - - * parseinfo.c (Parse_Info): Treat matching lines with bad expansions - as errors rather than just ignoring. - -2000-02-10 Larry Jones <larry.jones@sdrc.com> - - * edit.c (edit): Check for invalid characters in hostname and CurDir. - (Reported by "Andrew S. Townley" <atownley@informix.com>.) - * sanity.sh (devcom2): New tests for above. - -2000-02-10 Larry Jones <larry.jones@sdrc.com> - - * cvs.h: Always #include "server.h" to prevent compile errors when - neither CLIENT_SUPPORT nor SERVER_SUPPORT is defined. - (Reported by "Crow, Ian" <ian.crow@linklaters.com>.) - * 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 <http://developer.redhat.com/> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <kj@sourcegear.com> - - * 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 <bcolle@ilx.com>, and is his completely. - -2000-01-22 Jim Kingdon <http://developer.redhat.com/> - - * sanity.sh (emptydir): Add a case in which one might hope for a - non-Emptydir result, but which result? - -2000-01-18 Larry Jones <larry.jones@sdrc.com> - - * main.c (main): Allow -z0 to disable gzip compression. - -2000-01-17 Larry Jones <larry.jones@sdrc.com> 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 <larry.jones@sdrc.com> - - * mkmodules.c (init): Create CVSROOT/Emptydir to avoid problems - with users not having sufficient permissions to create it later. - -2000-01-04 Larry Jones <larry.jones@sdrc.com> - - * 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 - <pavel_roskin@geocities.com>.) - - * hardlink.c: sizeof (char) is 1, by definition. - * logmsg.c: Ditto. - * rcs.c: Ditto. - -2000-01-03 Karl Fogel <kfogel@red-bean.com> - - * filesubr.c, subr.c (backup_file): moved this function from - filesubr.c to subr.c, at JimK's suggestion. - -2000-01-03 Jim Kingdon <http://developer.redhat.com/> - - * sanity.sh (clean): Test the contents of the .#cleanme.txt.1.1 - file, not just its existence. - -2000-01-03 Karl Fogel <kfogel@red-bean.com> - - * 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 <larry.jones@sdrc.com> - - * sanity.sh (clean): Fix up expected output. - -2000-01-02 John P Cavanaugh <cavanaug@sr.hp.com> - and Karl Fogel <kfogel@red-bean.com> - - 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 <http://developer.redhat.com/> - - * 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 <larry.jones@sdrc.com> - - * release.c (release): Use fputs to echo lines from update instead - of printf to avoid problems with lines containing "%". (Reported - by Jean-Luc Simard <Jean-Luc.Simard@matrox.com>.) - - * 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 <larry.jones@sdrc.com> - - * 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 <pavel_roskin@geocities.com> - and Larry Jones <larry.jones@sdrc.com> - - * 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 <kfogel@red-bean.com> - - * Revert previous change -- it doesn't work remotely yet. - -1999-12-10 John P Cavanaugh <cavanaug@sr.hp.com> - and Karl Fogel <kfogel@red-bean.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <kfogel@red-bean.com> - - * login.c (logout): free `tmp_name' when done. - Correct a comment. - -1999-11-29 Larry Jones <larry.jones@sdrc.com> - - * cvs.h, error.c, import.c: Rename fperror to avoid name clash - on LynxOS. (Reported by Markus Braun <MarkusBraun@gmx.de>.) - -1999-11-23 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * server.c (switch_to_user): Correct setgid error messages. - -1999-11-19 Karl Fogel <kfogel@red-bean.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <kfogel@red-bean.com> - - * 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 <http://developer.redhat.com/> - - * 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 <http://developer.redhat.com/> - - * 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 <kj@sourcegear.com> - - * admin.c: made the -H option do what it is documented to - do. a - -1999-11-08 Tom Tromey <tromey@cygnus.com> - - * client.c (connect_to_gserver): Print more error text if gssapi - initialization fails. From Assar Westerlund <assar@sics.se>. - -1999-11-06 Larry Jones <larry.jones@sdrc.com> - - *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 <http://developer.redhat.com/> - - * 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 <larry.jones@sdrc.com> - - * 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 <kfogel@red-bean.com> - - * 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 <http://developer.redhat.com/> - - * 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 <larry.jones@sdrc.com> - - * 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 <kfogel@red-bean.com> - - 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 <kfogel@red-bean.com> - - * 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 <larry.jones@sdrc.com> - - * sanity.sh (dotest_sort): Old versions of tr don't understand \t - so use a literal tab instead. - -1999-10-21 Larry Jones <larry.jones@sdrc.com> - - * 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 <kj@sourcegear.com> - - 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 <larry.jones@sdrc.com> - - 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 <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * log.c (log_parse_revlist): Handle peculiar revision specs like - "-r.", "-r:", and "-r," correctly. (Thanks to Pavel Roskin - <pavel_roskin@geocities.com> for submitting a patch, this fix is - somewhat different.) - * sanity.sh (log): New tests for above. - -1999-09-15 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (basica-8b1): New test to check fix for bad diff options - causing cvs to crash. - -1999-09-02 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <hide@koie.org>.) - -1999-08-25 Larry Jones <larry.jones@sdrc.com> - - * 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 <chris.cameron@ot.co.nz>.) - -1999-08-24 Larry Jones <larry.jones@sdrc.com> - - * commit.c (check_fileproc): Don't crash when a file has no - repository, just treat it as unknown. (Reported by Stefaan - Diericx <stefaan.diericx@argenta.be>.) - * sanity.sh (errmsg2): New tests, for this fix. - -1999-08-18 Larry Jones <larry.jones@sdrc.com> - - * update.c (special_file_mismatch): Initialize *_hardlinks to - avoid trying to free garbage later on. (Reported by Jan - Scheffczyk <herta@Xterminator.StudFB.UniBw-Muenchen.de>.) - -1999-08-17 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (basicc-11): Older versions of sh don't understand - ``if ! test...''. (Patch submitted by David J N Begley - <david@avarice.nepean.uws.edu.au>.) - -1999-08-17 Larry Jones <larry.jones@sdrc.com> - - * 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 <laurent.duperval@cgi.ca>.) - -1999-08-16 Larry Jones <larry.jones@sdrc.com> - - client.c: Eliminate redundant #if. (Patch submitted by Assar - Westerlund <assar@sics.se>.) - -1999-07-30 Larry Jones <larry.jones@sdrc.com> - - * 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 <larry.jones@sdrc.com> - - * 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 <eric@sourcegear.com> - - * version.c: Push version number to 1.10.7.1. - - * version.c: Version 1.10.7. - -1999-07-28 Eric Sink <eric@sourcegear.com> - - * sanity.sh: before running basicc-11, we need to see if - the cwd has been deleted (by basicc-8). If so, we - recreate it to allow basicc-11 to proceed. This may be - something that only happens under the Linux 2.2 kernel. - -1999-07-18 Karl Fogel <kfogel@floss.red-bean.com> - - * edit.c (notify_do): chop newline, if any, from the value - obtained from CVSROOT/users. Otherwise it just gets passed along - in the argument to the notification program (usually mail), which - will misinterpret it as signifying the end of the command. - -1999-07-19 Larry Jones <larry.jones@sdrc.com> - - * rcs.c (RCS_delete_revs): In the WIN32 kludge, be sure that the result - of RCS_getexpand is not NULL before trying to use what it points to. - (Patch submitted by Timothy L. Taylor <ttaylor@mitre.org>.) - -1999-07-16 Tom Tromey <tromey@cygnus.com> - - * admin.c (admin): Allow `-k' options to be used unrestricted. - -1999-06-23 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (symlinks2): New test, for symlinks in working - directory without PreservePermissions. This test (modulo a few - details not relevant to testing whether we are following symlinks) - worked remote as of now, or either remote or local for CVS 1.9. - * subr.c (get_file): Revert 1998-02-15 change to special-case - symlinks. This makes the above test work local too. - * rcs.c (RCS_checkin): Move the logic to handle special-case - symlinks (and other files other than regular files) here, and make - it only happen if PreservePermissions is on. - -1999-06-18 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (devcom3-9a): Be less specific about the expected - error message (BSD/OS 4.0 has a bug that can cause exec* to fail - with EACCES instead of ENOENT). - -1999-06-08 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (diff-4, dirs2-10, tagf-13, importc-7, conflicts2-142b8): - Use ${PROG} instead of "cvs". - -1999-06-05 Jim Kingdon <http://www.cyclic.com> - - * recurse.c (do_recursion, do_dir_proc): Make the SERVER_ACTIVE - #ifdef be only around the check for server_active. Modulo a few - cosmetic tweaks, same as a patch submitted by Johannes Stezenbach - of propack-data.de. - -1999-06-01 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh: Add comment about rcs2-7 failures on certain days. - - Make "cvs status -v" on a removed file work: - * status.c (cvsstatus): Reindent the client code. - (status_fileproc): Don't need a CVS/Entries listing to show the - tags. - * sanity.sh (rmadd2): New test rmadd2-16 tests the existing - behavior with "cvs log"; new test rmadd2-17 tests the new behavior - with "cvs status". - - * sanity.sh (basicc): To match no output in dotest, put the empty - regexp first. Remove tests which check that first-dir exists, - since that isn't true in the case where the OS let us delete it. - (dotest_internal): Fix so that things work with two regexps, with - an empty one first. - -1999-05-28 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (server-4): Replace bogus directory with real one since - the server now checks it. - -1999-05-27 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (spacefiles): Clean up -c, top, and -b at end. - (spacefiles, files): Fix bad references to CVSROOT_DIRNAME. - - Fix two problems pointed out by Olaf Kirch of swb.de/caldera.de: - * server.c (outside_root): New function, contains expanded version - of code from serve_directory. - (serve_directory): Call outside_root. - (outside_dir): New function - (serve_modified, serve_is_modified, serve_notify, - serve_questionable, serve_unchanged): Call outside_dir. - * sanity.sh (server2): New tests, for these fixes. - -1999-05-26 Jim Kingdon <http://www.cyclic.com> - - * cvs.h, subr.c (xmalloc): Return void* not char*, like xrealloc - has done for some time. - * modules.c (do_module): If we find the module as a directory/file - (rather than in the modules file), skip a bunch of processing - which was unnecessary and also broken in most of the cases - now tested for by the spacefiles sanity.sh test. - * sanity.sh (spacefiles): New test, for specifying filenames - (containing spaces, or starting with '-', or starting with '/') to - "cvs co". - -1999-05-25 Jim Kingdon <http://www.cyclic.com> - - * client.c (update_entries): Make the old DONT_USE_PATCH code the - only code. This means that if people are still on CVS 1.9 - servers, then CVS will fall back to transferring entire files. - This is better than looking for an external "patch" program which - causes no end of troubles (especially on Windows, but someone just - posted to info-cvs about a problem with the Solaris patch). (This - change was run by devel-cvs and feedback was positive). - - * subr.c (xmalloc, xrealloc): The new error.c does not support - %lu; use sprintf instead. - -1999-05-25 Derek Price - <http://www-personal.engin.umich.edu/~oberon/resume.html> - - * sanity.sh (server): Escaped a few more newlines in - another awk script. Solaris awk still don't like 'em. - -1999-05-25 Derek Price - <http://www-personal.engin.umich.edu/~oberon/resume.html> - and Jim Kingdon - - * log.c: Remove comment which said "you can delete [this line]" - and which stuck around for over 3 years. - * sanity.sh (errmsg2 & tagdate): Added tests to prove the - current functionality with respect to combining -r and -D. - -1999-05-20 Larry Jones <larry.jones@sdrc.com> - - * server.c (pserver_authenticate_connection): Previous changes - broke verify_and_exit (reported by Robert Fitzsimons, thanks). - * sanity.sh (pserver): New tests pserver-7 and pserver-8 for this. - -1999-05-18 Derek Price - <http://www-personal.engin.umich.edu/~oberon/resume.html> - - * sanity.sh (keyword2): Escaped a newline in an awk script. - Apparently Solaris awk don't like 'em. - -1999-05-18 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (basicc): Allow the behavior whereby unlink(".") - succeeds. Reported by Jeremy Buhler and Pavel Roskin. - -1999-05-17 Steve Cameron of Compaq - - * sanity.sh: Modified to no longer use "test -e" for existence - test as it has turned out to be not portable enough. Instead use - "test -f", "test -d", etc. - [SCO Unixware 7 apparently doesn't always support it -kingdon] - -1999-05-17 Jim Kingdon <http://www.cyclic.com> - - * version.c: Push version number to 1.10.6.1. - - * version.c: Version 1.10.6. - -1999-05-16 Jim Kingdon <http://www.cyclic.com> - - * update.c (patch_file): When we are passing vn_rcs to - RCS_checkout, pass vn_tag as well. - * sanity.sh (keyword): In test keyword-22, test for the fixed - behavior rather than the buggy behavior. Adjust keyword-23. Add - test keyword-24, to see whether keyword-23 really worked. - -1999-05-12 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (pserver-4, pserver-5): Bogus error messages from - non-root initgroups on some 4.4BSD derived systems now show up - in different places in the output. - -1999-05-12 Jim Kingdon <http://www.cyclic.com> - - * import.c (import): Don't allow the user to supply a repository - directory which takes us out of the cvsroot. - * sanity.sh (importc): New tests importc-10 to importc-12, for this. - -1999-05-11 Larry Jones <larry.jones@sdrc.com> - - * server.c (serve_notify): Allocate enough memory to hold the - "misformed Notify request" message in pending_error_text. - -1999-05-11 Jim Kingdon <http://www.cyclic.com> - - * server.c (switch_to_user): Ignore EPERM from initgroups. Fixes - pserver-4 in testsuite. - (pserver_authenticate_connection): Only print "I LOVE YOU" after - switch_to_user has come back successfully. - - * server.c (pserver_authenticate_connection): Call error_exit - rather than reinventing the wheel ourselves. - (switch_to_user): Check for errors from setuid, setgid, and - initgroups. Fix the #ifdef's (the previous code would skip the - setuid call if SETXID_SUPPORT). - -1999-05-10 Jim Kingdon <http://www.cyclic.com> - - * server.c (serve_notify), edit.c (notify_do): Check for - and reject characters which will get confused with delimiters. - * sanity.sh (server): New tests server-7 through server-15 test - for this and for other notify behaviors. - - * rcs.c (RCS_tag2rev): Also look for a physical branch with - RCS_getversion. - * sanity.sh (tagf): Adjust tagf-12 and following tests to test for - the fixed behavior rather than the broken behavior. - -1999-05-07 Jim Kingdon <http://www.cyclic.com> - - * server.c (server_notify): Also set last_node to NULL. - * sanity.sh (server): New tests server-6 and server-7, for this. - -1999-05-05 Jim Kingdon <http://www.cyclic.com> - - * rcs.c (rcs_internal_lockfile): Remove unused variable lockfile. - - * add.c (add): Look for directories with the same name in a - different case where appropriate (analogous to fopen_case). - In client code, add comment about how this doesn't do quite - everything. - -1999-05-03 Jim Meyering <meyering@ascend.com> - - Remove rcs-style ,file, lock files upon signal. - * rcs.c (rcs_lockfile): New file-scoped global. - (rcs_cleanup): New function (similar to patch_cleanup). - (rcs_internal_lockfile): Register rcs_cleanup the first time this - function is called. Rename uses of local `lockfile' to refer to new - global, `rcs_lockfile'. Don't free the lock file name string, now - that it's global. - (rcs_internal_unlockfile): Rename `lockfile', as above, and carefully - free and NULL-out the global, rcs_lockfile. - -1999-04-30 Jim Kingdon <http://www.cyclic.com> - - * rcs.c (annotate_fileproc): Don't cast NULL in passing it to - RCS_deltas. Because there is a prototype in scope the cast is - unnecessary (per HACKING's ANSI C or SunOS4 rule), and in fact it - was causing failures on UNICOS because it cast to size_t instead - of size_t*. (Thanks to Dean Kopesky for reporting this). - -1999-04-29 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh: If invoked without any arguments, print a usage - message (thanks to Pavel Roskin for a report/patch). - - * run.c (piped_child): Make the error messages more verbose. - (close_on_exec): Reindent. - * sanity.sh (devcom3): Several errors are possible in devcom3-9a. - Adjust for change to piped_child error message. - -1999-04-28 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (devcom3): Add some tests of the CVS/Notify file and - disconnected "cvs edit". - - * main.c (opt_usage): Remove -b. - -1999-04-20 Derek Price - <http://www-personal.engin.umich.edu/~oberon/resume.html> - - * rcs.c (RCS_delete_revs): RCS_delete_revs uses an - RCS_checkout call to get a new copy of a revision to be - used internally after old revisions were deleted and it was - performing keyword substitutions. This munged all the - the revisions of the file on the branch containing the - deleted revisions and its sub-branches, as the original they - were being patched from was incorrect. Corrected this by - passing in "-ko" as an option to RCS_checkout. - * sanity.sh (keywordlog): modified this test to verify the - correct behavior of 'cvs admin -o'. - [Fixed use of \$ in keywordlog test; added code in RCS_delete_revs - to abort on binary file on Windows -kingdon] - -1999-04-21 Derek Price - <http://www-personal.engin.umich.edu/~oberon/resume.html> - and Jim Kingdon - - * tag.c (tag_check_valid): A bug was causing CVS to spin - indefinately when -j:<date> was specified. CVS now returns - an error. - * sanity.sh: Added a test (tagdate-12) to test this. - -1999-04-19 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (backuprecover): Clean up the repository at the end. - -1999-04-18 Derek Price - <http://www-personal.engin.umich.edu/~oberon/resume.html> - - * sanity.sh added a test (backuprecover) to test cvs behavior - with a repository that is out of date relative to the - developer's workspaces. - [Fix --keep code; move test to "Repository Storage" section since - it doesn't really exercise the diff/diff3 library. -kingdon] - -1999-04-13 Derek Price - <http://www-personal.engin.umich.edu/~oberon/resume.html> - - * sanity.sh (diff): Tests to verify correct operation of - the --ifdef parameter to cvs diff. - [indentation fixed -kingdon]. - -1999-04-13 Derek Price - <http://www-personal.engin.umich.edu/~oberon/resume.html> - for Noah Friedman <friedman@splode.com> - - * diff.c (diff): Put "--ifdef=" in opts string, not "-D"; the - latter is confused by pserver for a date spec. - -1999-04-14 Jim Kingdon <http://www.cyclic.com> - - * fileattr.h: Adjust comments to reflect the official version of - the fileattr format now being in cvs.texinfo. - -1999-04-05 Jim Kingdon - - * sanity.sh (watch5): Remove nonstandard --keep code. Don't pass - -f to rm when cleaning up (that tends to mask bugs). Add watch5 - to list of tests at start. Add comment explaining why we consider - the behavior we test for the right one. Rename a few tests which - had been erroneously named watch6* instead of watch5*. - * client.c (update_entries): Add comment with brief discussion of - whether there is a better way. - -1999-04-05 Derek Price - <http://www-personal.engin.umich.edu/~oberon/resume.html> - - * client.c (update_entries): Only call mark_up_to_date - (which deletes the CVS/Base/<filename> file for watched - and edited files) on commit. - * sanity.sh: Make sure the CVS/Base/<filename> file for - a watched and edited file is not removed on a status or - update of a touched/unmodfied file. - -1999-03-30 Larry Jones <larry.jones@sdrc.com> - - * client.c (get_responses_and_close), commit.c (commit), - update.c (do_update): If the sleep(1) call returns prematurely - (due to the way wakeup is scheduled or receiving a signal), do - it again. - -1999-03-26 Jim Kingdon <http://www.cyclic.com> - - * server.c (server): Add comment about Gzip-stream vs. RQ_ROOTLESS. - - * sanity.sh (modules3-11b): Adjust exact text of error message to - reflect 1999-03-24 change to dirswitch. - -1999-03-25 Jim Kingdon <http://www.cyclic.com> - - * admin.c (admin): Make argument to -e optional, to match the - documentation. - * sanity.sh (admin-19a-2): Test for this. - - * server.c (serve_root): Update comment about checking for missing - Root request. - -1999-03-24 Jim Kingdon <http://www.cyclic.com> - - * server.c (dirswitch): Also check dir here, similar to - what server_pathname_check does for other cases. - * sanity.sh (files): Adjust files-14 to test for this. - -1999-03-24 Derek Price - <http://www-personal.engin.umich.edu/~oberon/resume.html> - and Jim Kingdon - - * sanity.sh: added a test (files-13) to test .. indirection - in a path and another (files-14) to make sure we still fail - out when the '..' indirection takes us into the $CVSROOT - directory or beyond. - -1999-03-24 Larry Jones <larry.jones@sdrc.com> - - * rcs.c: Change enum constants ADD and DELETE to something less - likely to run into conflicts. - -1999-03-21 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (tagf): New test, tests for moving a branch tag to a - non-branch tag and trying to recover. - -1999-03-12 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (branches): Tweak test branches-5 to test the case in - which one modifies a file and then branches it. - -1999-03-09 John Bley of duke.edu - - * mkmodules.c (filelist): Missed a NULL in this struct (should - have 3 members, only had 2). - -1999-03-07 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (Index): Rename new test from rm_CVS/Root to rmroot - (we don't have a formal rule about funky punctuation in test names - but both underscore and a slash is too funky for me :-)). - Reindent a few tests which were off. - - * root.c: Remove the sentence which had the improper English; - there isn't really a need for that sentence and it isn't - particularly accurate any more. - -1999-02-27 Derek Price - <http://www-personal.engin.umich.edu/~oberon/resume.html> - - * sanity.sh: Added rm_CVS/Root test to test that CVS uses - $CVSROOT rather than dumping core when running remotely and - the admin file CVS/Root is deleted from the workspace. - - Also, altered a few 'cvs commit' 's in regular expressions to - fit the .${PROG} commit. portability syntax. - - * recurse.c: Stopped CVS from dumping core in the case tested - above. - - * root.c: Fixed somebody's improper english. - -1999-02-25 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (keyword2-12): Use ${QUESTION} instead of ? in the - expected result. - -1999-02-24 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (keyword2): Restore the original \\\$ instead of $. - The latter ends up working due to various kludgy semantics in the - shell and regular expressions, but the former is cleaner. - - * sanity.sh (keyword2): Protect keywords against accidental - expansion in sanity.sh itself (most occurrences had this, but not - all). - -1999-02-23 Derek Price <http://www.cyclic.com> - and Jim Kingdon. - - * sanity.sh (keyword2): New test, tests for merging with -kk. - -1999-02-22 Jim Kingdon <http://www.cyclic.com> - - * version.c: Ease version number to 1.10.5.1. - - * version.c: Version 1.10.5. - -1999-02-18 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (files): New test, for a relatively obscure spurious - "Up-to-date check failed" in client/server. - - * main.c (lookup_command_attribute): Don't check for "history" - twice. - -1999-02-17 Jim Kingdon <http://www.cyclic.com> - and Hallvard B Furuseth - - * root.c (parse_cvsroot): Rearrange ifdefs to squelch possible - warnings about statement not reached. - -1999-02-16 Jim Kingdon <http://www.cyclic.com> - - * recurse.c (start_recursion): If we are skipping the current - directory (due to it being from the wrong repository), also adjust - the arguments we send to the server accordingly (like we already - do for the case in which there is no CVS directory). - * sanity.sh (multiroot4): New test, for this. All these tests had - passed locally, but remote multiroot4-12 tests for this fix. - (multiroot): Adjust multiroot-diff-1, multiroot-update-2, - multiroot-tag-1, multiroot-status-1, multiroot-update-3, and - multiroot-log-1 to reflect the cosmetic change this produces (one - less "Diffing ." message). - (multiroot2): multiroot2-8 likewise. - -1999-02-10 Jim Kingdon <http://www.cyclic.com> - - * tag.c (cvstag): Don't pass SEND_NO_CONTENTS if -c specified. - * sanity.sh (tagc): New test, for various tag -c behaviors. - Test tagc-6 tests for this fix. - -1999-02-09 Jim Kingdon <http://www.cyclic.com> - - * error.c (error): Rewrite to no longer use vasprintf (see - ../lib/ChangeLog for rationale). Note the slight change in - interface - callers which want %8.8s or similar formats need to - call sprintf. - * lock.c (lock_wait, lock_obtained): Use sprintf. - -1999-02-08 Jim Kingdon <http://www.cyclic.com> - - * rcs.c (RCS_delete_revs): Pass -a to diff_exec. - * sanity.sh (binfiles3): New tests binfiles3-9 through - binfiles3-13 test for this fix. - * sanity.sh (binfiles): New tests binfiles-o4 and binfiles-o5 - (which don't test this bug, just on general principles). - -1999-02-04 Jim Kingdon <http://www.cyclic.com> - - * lock.c (lock_name): Permissions of directories in LockDir - shouldn't depend on the umask. - * sanity.sh (lockfiles): Set umask and CVSUMASK, to test for this. - -1999-02-01 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (keywordlog): New tests keywordlog-22 and - keywordlog-23 test keyword expansion and $Log. Adjust other tests - so that revisions differ more from each other, so this is a - better test. - -1999-01-29 Jim Kingdon <http://www.cyclic.com> - - * commit.c (checkaddfile): If options is "", treat it the same as - NULL. Centralize this check, and the one for it starting with - "-k", at the start of the function. - - * rcs.c, rcs.h (RCS_setexpand): New function. - * admin.c (admin_fileproc): Access keyword expansion field via - RCS_getexpand and RCS_setexpand, rather than directly. - * commit.c (checkaddfile): When resurrecting, set the keyword - expansion mode. - * sanity.sh (binfiles3): Adjust tests binfiles3-7 and binfiles3-8 - for the new behavior. - -1999-01-27 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (multiroot3): Add new variant of multiroot3-10 test - for RELATIVE_REPOS. Move multiroot3-11 test out of the - conditionals; it works the same for remote or local, - RELATIVE_REPOS or no. - - * options.h.in: Make RELATIVE_REPOS the default, as has been - announced as a future direction since 1997-10-11. - * sanity.sh (multiroot): Tweak multiroot-update-1a and - multiroot-update-1b tests to work with either RELATIVE_REPOS or - non-RELATIVE_REPOS. - - * sanity.sh (client-9): Don't assume the time zone. - -1999-01-26 Jim Kingdon <http://www.cyclic.com> - - Fix one facet of the "cvs add -kb" re-adding problem (the other - known facet is tested for by binfiles3-8). - * add.c (add): When re-adding a file, set the keyword expansion - as we normally would. - * sanity.sh (binfiles3): New test binfiles3-6a tests for this. - -1999-01-22 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (rmadd2): New tests, for undoing a commit. - -1999-01-21 Eric Mumpower <nocturne@cygnus.com> - - * sanity.sh (reposmv): Actually modify CVSROOT in current - environment when calling functions, rather than trying to achieve - the same effect with "CVSROOT=foo functionname". (Many common - bourne shells, including those in SunOS and Solaris 2.4-2.7, - do not properly handle "ENVVAR=foo command" when "command" is - a user-defined shell function rather than an actual executable.) - -1999-01-15 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (rcs3): Redirect awk's stdin to /dev/null like all the - other awk invocations. GNU awk seems not to read stdin in this - case, but that behavior is hard to reconcile with the Single Unix - Spec and some awks don't do it. - - * sanity.sh (binfiles, binfiles2, binfiles3, server): Use the same - tr trick as in rcs3. People don't seem to have been complaining, - and this should fix server-4 for HPUX. - -1999-01-14 Jim Kingdon <http://www.cyclic.com> - - * client.c (recv_line): If the line we are reading contains a - character which would sign-extend to EOF, don't treat it as end of - file. recv() doesn't report end of file this way and this might - fix bugs with 0xff characters. - -1999-01-14 Larry Jones <larry.jones@sdrc.com> - - * client.c (recv_line): Handle EOF from server. - - * sanity.sh (importc-8, importc-9): Accept anything in the seconds - fields of the timestamps since touch doesn't set it reliably. - (This isn't great, but it's better than nothing.) - -1999-01-14 Jim Kingdon <http://www.cyclic.com> - - * run.c (run_exec): Adjust comment about vfork; this isn't the place - to get into a treatise about fork performance vs. vfork - performance but it isn't quite as simple as whether one has - copy-on-write. - -1999-01-13 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (dotest_fail): Handle spurrious output from assert better. - - * sanity.sh (rcs3-4, rcs3-5a): Handle even more variants of the - assertion failure message. - -1999-01-12 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (mtfr-3): ls behavior varies wildly on nonexistant files, - just use echo instead. - -1999-01-11 Jim Meyering <meyering@ascend.com> - - * sanity.sh (mkmodules-temp-file-removal): New test, for this. - * mkmodules.c (mkmodules): Remove each `CVSROOT/.#[0-9]*' temporary - file that's used to check out files listed in CVSROOT/checkoutlist. - Remove extra semicolon at end of line. - -1999-01-11 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (rcs3-5a): Allow for multiple lines of output before the - assertion failure message. - - * sanity.sh (lockfiles-6, client-8): Work around bug in HP-UX chmod - (doesn't allow anything to follow omitted permissions). - -1999-01-09 Jim Kingdon <http://www.cyclic.com> - - * client.c (set_sticky): Nonfatal error if we can't write it. - * sanity.sh (dirs2-8 through dirs2-14): New tests, for this. - - * sanity.sh (rcs3): Write NUL character with tr not awk, in - accordance with Single Unix Specification. Hopefully will fix - rcs3-7 for HPUX. Will not work on SunOS4, but then again neither - did the old syntax. - -1999-01-05 Jim Kingdon <http://www.cyclic.com> - - * client.c, update.c: Rename MD5* functions to cvs_MD5* per - corresponding change to ../lib/md5.h. - -1999-01-03 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (client): Give file1 a predictable mode so that the - output in client-9 will not depend on the umask of the user - running the tests. - -1998-12-29 Jim Kingdon <http://www.cyclic.com> - - * client.c (client_senddate): Use date_to_internet rather than - using our own "5/26/1997 13:01:40 GMT" date format. - * main.c (date_to_internet): Check for errors from sscanf. Always - send a four digit year. Send hours, minutes, and seconds as two - digits per RFC822. - * sanity.sh (client): New tests client-8 and client-9 test for this. - - * sanity.sh (rcs2): New tests rcs2-6 through rcs2-8 test for fix - to lib/getdate.y (before the fix, "100 months" or "8 years" would - tend to mean the year 1969, thus the tests would give "cvs update: - file1 is no longer in the repository"). - -1998-12-28 Larry Jones <larry.jones@sdrc.com> - - * entries.c (Register): Return if unable to open log file to avoid - referencing the invalid file pointer. - * sanity.sh (dirs2-7): With above change, no longer fails. - * sanity.sh (rcs3-5a): Another assertion failure message. - * sanity.sh (pserver-4, pserver-5): Some 4.4BSD derived systems spit - out bogus error messages when initgroups is called as non-root. - -1998-12-23 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (rcs3, dotest_fail): The assertion failure message varies - wildly between different systems and the resulting abort call can - even result in spurrious output. Fix the regexp to accept nearly - anything containing some kind of assertion failure and ensure that - any spurrious output ends up in the output file instead of on the - terminal. - -1998-12-23 Jim Kingdon <http://www.cyclic.com> - - * admin.c, checkout.c, commit.c, cvsrc.c, expand_path.c, - history.c, ignore.c, import.c, log.c, mkmodules.c, modules.c, - myndbm.c, parseinfo.c, rcs.c, remove.c, rtag.c, status.c, subr.c, - tag.c, wrapper.c: Cast all char's to unsigned char before passing - them to ctype.h functions (isalpha, isgraph, isalnum, isspace, - isdigit, isprint, isupper). Whether using ctype.h is the right - thing at all is unclear to me (having the server depend on locale - seems wrong, as we don't necessarily have any good way to set the - right locale, if there even is such a concept as 'right' locale in - this context), but as long as we use ctype.h we might as use it - according to the standards (this affects systems where plain char - is signed but users supply characters with the 8th bit set). - Thanks to Paul Eggert for suggesting this. - -1998-12-22 Jim Kingdon <http://www.cyclic.com> - - * sanity.sh (rcs3): Oops, the earlier fix for srcdir only fixed - the non-remote case, not the remote case. Fix the other occurrence. - -1998-12-22 Jim Kingdon - - * sanity.sh (rcs3): The assertion failure message varies slightly - depending on whether CVS was built with srcdir != ".". Fix regexp. - -1998-12-21 Jim Kingdon - - * rcs.c (RCS_getdate): Reindent Jim Meyering's change; remove - unused variable x_vers. - - * rcs.c: When printing an unexpected character we found in the RCS - file, print it in hex rather than as a character (see comment for - rationale). - * sanity.sh (rcs3): Adjust rcs3-2 and rcs3-7 tests accordingly. - - * sanity.sh (rcs3): New test, for some error handling cases - involving parsing RCS files. - -1998-12-16 Jim Meyering <meyering@ascend.com> - - * rcs.c (RCS_getdate): Handle the case in which a file is first - imported after its initial version has been created. - * sanity.sh (import-after-initial): New test for that. - -1998-12-17 Jim Kingdon - - * server.c (serve_root): Pserver_Repos only exists if - AUTH_SERVER_SUPPORT is defined. - -1998-12-12 Jim Kingdon, and Derek R. Price of Stortek. - - * sanity.sh (multiroot): Change + to ${PLUS}. - -1998-12-12 Jim Kingdon, and Gary Young of Motorola - - * sanity.sh (admin): In tests admin-13, admin-25, and admin-29, - allow 4 digit year in addition to 2 digit year. - -1998-12-12 Jim Kingdon - - * sanity.sh (log): New tests log-14a and log-14b test for -rHEAD - and for HEAD as (nonexistent) file name. - -1998-12-02 Jim Kingdon - - * version.c: Squish version number to 1.10.4.1. - - * version.c: Version 1.10.4. - -1998-11-24 Jim Kingdon - - * recurse.c (do_file_proc): Check for errors from RCS_parse. - * sanity.sh (rcslib-symlink-7 through rcslib-symlink-10): New - tests, test for this. - - * sanity.sh (reposmv-2): Adjust for 22-Nov change to Find_Names. - - * entries.c (Register): If we can't write Entries.Log, make it a - nonfatal error. - * sanity.sh (dirs2): Test for this fix. - - * sanity.sh (dirs2): Clean up working directory at end of test. - -1998-11-23 Jim Kingdon - - * sanity.sh (dirs2): New test, for some more cases involving - deleting directories and such. - - * sanity.sh (dirs): Update for yesterday's change in Find_Names - error handling. The error in dirs-4 is fairly different now; in - dirs-3 and dirs-3a it is the obvious change. - -1998-11-22 Jim Kingdon - - * sanity.sh (release): Move the commments listing "cvs release" - tests from modules2-6 to here. - * release.c (release): Update comment to reflect "? foo" case. - - * find_names.c (Find_Names): If we can't read the repository, make - it a nonfatal error. Tell the caller whether this happened. - (find_rcs): Add comment regarding this behavior. - * recurse.c (do_recursion): If Find_Names gives an error, skip - the directory and print a message saying so. - * sanity.sh (modes3): New test, for this. - -1998-11-18 Jim Kingdon - - * rtag.c (rtag_usage), tag.c (tag_usage): Use "-r rev" - consistently. - - * sanity.sh (conflicts3): Tests conflicts3-24 through - conflicts3-28 test for another case similar to conflicts3-22. - -1998-11-14 Jim Kingdon - - * sanity.sh (diff): New test, for now just tests for the "I know - nothing" message. - - * sanity.sh (conflicts2-142b7 through conflicts2-142b11): New - tests; resurrecting doesn't work from one level up. - - * sanity.sh (mwrap-7): Remote prints the messages in a different - order. - -1998-11-13 Jim Kingdon - - * tag.c (check_fileproc): Log tag deletions. - * rtag.c (check_fileproc): Likewise. - * sanity.sh (taginfo-14 through taginfo-18): New tests, for - these behaviors. - -1998-11-12 Jim Kingdon - - * sanity.sh (mwrap-7): Update for the noexec fix. - - * server.c (server_copy_file): Add comment about noexec. - - * update.c (checkout_file): Handle noexec case involving revbuf - and modes. - (update_fileproc): In case T_NEEDS_MERGE, let merge_file take care - of noexec, so it can tell the user if there would be conflicts. - (merge_file): Print "conflicts found in FILE" message - regardless of noexec. Add comment about checking for whether the - file already contained the changes, and noexec. - * sanity.sh (conflicts-192a): New test, for this. - -1998-10-20 Jim Kingdon - - Use the gzip library on the server. Probably doesn't speed things - up as currently implemented, but does avoid hassles in terms of - finding an external gzip program. - * zlib.c, server.h (gunzip_and_write, read_and_gzip): Now returns - whether a fatal error occurred, rather than expecting error (1, - ...) to work. - * client.c (update_entries, send_modified): Change callers. - * server.c (receive_file): Rewrite gzip code to use - gunzip_and_write rather than filter_through_gunzip. - (server_updated): Likewise, use read_and_gzip rather than - filter_through_gzip. - * client.c, client.h (filter_through_gzip, filter_through_gunzip), - run.c, cvs.h (filter_stream_through_program): Removed; no longer used. - * sanity.sh (server): New tests server-4 and server-5 test - this feature (note that CVS 1.10 also passes these tests; the - behavior is supposed to be unchanged). - -1998-10-19 Jim Kingdon - - * sanity.sh (multiroot3): New test, tests for a few more - multiroot cases. - - * lock.c (lock_name): Set the permissions on each directory we - create to that of the parent directory. - * sanity.sh (lockfiles): New chmod and tests lockfiles-7a and - lockfiles-7b test for this. Adjust lockfiles-5 for new text of - error message. - -1998-10-15 Jim Kingdon - - * server.c (requests): Set RQ_ROOTLESS for "Set". - * sanity.sh (info): Also clean up $HOME/.cvsrc. - (server): Test that we can send Set before Root (had been tested - by crerepos-6b, but only if you ran the info test first). Tests - for this fix. - -1998-10-14 Jim Kingdon - - * subr.c (expand_string): Tweak the algorithm so that the size - that it allocates is generally a power of two. - -1998-10-14 Eivind Eklund and Jim Kingdon - - * commit.c (commit): For the client, don't worry about whether we - are root. - -1998-10-13 Jim Kingdon - - * server.h (struct request): Change status field to flags and add - RQ_ROOTLESS. - * client.c (handle_valid_requests, supported_request): Change - status to flags. - * server.c (requests): Change status to flags. Add RQ_ROOTLESS. - * server.c (server): If not RQ_ROOTLESS, and we haven't gotten a - Root request, give an error. - -1998-10-12 Jim Kingdon - - * version.c: Slide version number to 1.10.3.1. - - * Version 1.10.3. - - * sanity.sh (modules2-17): Update for 9 Oct 1998 change to - update_dirent_proc. - -1998-10-11 Jim Kingdon - - * commit.c (checkaddfile, commit_fileproc): A numeric value for - 'tag' does not mean that we are adding on a branch. - * sanity.sh (keywordlog): Adjust this test, to test for this - (replaces comment saying we should be doing it). - (rmadd): Likewise. - - * sanity.sh (rmadd): New test, tests for various existing - behaviors with "cvs ci -r". - -1998-10-09 Jim Kingdon - - * update.c (update_dirent_proc): For local CVS, if the directory - does not exist in the working directory nor in the repository, - just skip it. - * sanity.sh (dirs): New tests dirs-3a, dirs-7 and dirs-8 test for - this and related behaviors. Note that the new behavior was also - the previous behavior for remote; we are only changing it for local. - - * wrapper.c, cvsrc.c, ignore.c: Add comments about ignoring .cvsrc - and friends if we can't find a home directory. - * expand_path.c (expand_path): If we can't find the home - directory, give an error rather than a coredump (or worse). - * login.c (construct_cvspass_filename): Don't use errno in error - message; get_homedir doesn't set it. Add comment about this - message. - -1998-10-07 Jim Kingdon <kingdon@harvey.cyclic.com> - - * diff.c (diff): Set variables to NULL at the start, and free - memory at the end. - * sanity.sh (multiroot2): Add tests for this (before the fix, - multiroot2-12 would abort with "no more than two revisions/dates - can be specified"). - -1998-10-06 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in (installcheck check): Remove references to RCSBIN; - they don't do anything now that RCSBIN is ignored. - - * client.c: Clean up horrible confusion about whether stored_mode - or stored_mode_valid (or nothing :-)) indicates whether - stored_mode is allocated. Should fix crashes (for example, on NT - when the server has renamed multiple files from uppercase to - lowercase). - - * sanity.sh (dirs): New tests, tests for some cases involving - admins who do surgery on the repository. - -1998-10-03 Johannes Stezenbach <johannes.stezenbach@propack-data.de> - - * vers_ts.c (Version_TS): If UTIME_EXPECTS_WRITABLE, if - necessary change the file to be writable temporarily to set its - modification time. - -1998-10-03 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (handle_error): Add comment about indicating which - errors are from the server. - -1998-10-01 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (devcom-180): Allow one digit day. - -1998-09-30 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): Don't call Name_Root if -d specified. - * recurse.c (do_recursion, do_dir_proc): Don't check CVS/Root - if -d was specified. - * import.c (import): Indentation fix. - * sanity.sh (multiroot): Update for this change. - (reposmv): New test, tests for this. - -1998-09-28 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (multiroot2): New test, tests some nested directory - cases. - -1998-09-25 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (multiroot): Change a few comments which said modules - when they meant directories. - -1998-09-25 Jim Meyering <meyering@ascend.com> - - * sanity.sh (devcom-180): Add 0-9 to the range of characters allowed - in hostname regexp. - -1998-09-25 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (log2): New test log2-7a tests for one error handling - case. Add a comment about another. - -1998-09-24 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Change crerepos test back to :ext: (for several - reasons; see comments). - -1998-09-24 Noel Cragg <noel@swish.red-bean.com> - - * sanity.sh (rcslib-symlink-5, rcslib-symlink-6): new tests to - check the operation of "tag" when there are symlinks in the - repository. - - * rcs.c (RCS_checkin): remove old code that resolved the symlink - and call resolve_symlink instead. - (RCS_rewrite): call resolve_symlink before doing anything else to - make sure we're operating on the file and not the symlink. - - * subr.c (resolve_symlink): new routine -- resolves a symbolic - link chain to its destination. - * cvs.h: add prototype. - - * sanity.sh (basica-6.2, basica-6.3): changed match expressions to - reflect new diff output. - - * rcs.c (make_file_label): generate labels for files that include - the pathname so that output from "cvs diff" is useable by patch. - Looks like I came up with the mods as Andy Piper - <andyp@parallax.co.uk>; his patch was on the Cyclic unofficial - patches page. - - * sanity.sh: change remote access method from ext to fork. This - results in a significant speed improvement when running the - testsuite. The ext method on my machine (i586 120MHz Linux 2.0.35 - with TCP wrappers installed) runs in 450% of the time of the local - method while the fork method runs in only 150% of the time of the - local method! Yow! Am I SWAPPING yet?! - (crerepos-6a, crerepos-6b): change to reflect different error - messages for fork method. - (modes-15): same. - - * client.c (connect_to_forked_server): new routine. - (start_server): call the above when method is fork_method. - - * root.c: add a new method named "fork". This method uses the - remote protocol, but does so by forking a "cvs server" process - directly rather than doing "rsh host cvs server" (for example). - This new method has few advantages for day-to-day use, but has - three important benefits for debugging: - - 1) Most secure installations these days don't allow rsh access. - With this new method, we can still test the remote protocol on - these machines because we don't need to be able to make a local - TCP connection. - - 2) Even if installations allow rsh access, they almost always - have TCP wrappers to check permissions by IP/hostname. This - causes a short delay for every connection. For invocations from - the command line, this doesn't matter much, but it adds up to a - significant amount of time when running the testsuite. - - 3) On machines that can't (or do not usually) provide rshd - access (I'm thinking of WNT/W95 in particular), we can now run - tests of the remote protocol using this method. Indeed, we can - run remote protocol tests on any machine that has an - implementation of piped_child(). - - (parse_cvsroot): handle new method. - (error_exit, xstrdup, isabsolute): new stub functions to use when - compiling root.c with the DEBUG option. - (main): fix a few typos. - * cvs.h (CVSmethod): add fork_method. - - * server.c (create_adm_p): use Emptydir as the placeholder - directory instead of "." to avoid problems with "cvs update -d" et - al. - -1998-09-22 Noel Cragg <noel@swish.red-bean.com> - - * sanity.sh (devcom-180): fixed typo in regexp. - - * main.c (main): remove need_to_create_root and related code - (including CVS_IGNORE_REMOTE_ROOT environment variable). The - current implementation (just removed) of rewriting the contents of - the CVS/Root file isn't desirable for a number of reasons: - - 1) Only the top-level CVS/Root directory is updated. If we're - really interested in pointing our WD at another CVSROOT, we - should have a separate command. - - 2) With the new multiroot mods, we don't ever want to rewrite - CVS/Root files in the way the removed code did. Consider: - - cvs -d repository1 co a - cd a - cvs -d repository2 co b - cvs -d repository2 update b - - The update command would rewrite the contents of a/CVS/Root to - the incorrect value. Bad. We then wouldn't be talking to the - correct repository for files in a. - - 3) The removed code seems to be a quick hack to support working - directories checked out from multiple repositories. With the - CVS_IGNORE_REMOTE_ROOT variable set, one could perform commands - as in example 2, above, without worring about updating CVS/Root - files. While in pre-1.10.1 recursive commands wouldn't handle - that working directory hierarchy, one could use commands like - "cvs foo -l" instead. While not great, this allows you (with a - lot of manual interaction) to have a multiroot WD. Since we now - have multiroot mods checked in, we don't need this code. - - (lookup_command_attribute): while we don't need the - CVS_CMD_USES_WORK_DIR flag anymore (since it only was supporting - the need_to_create_root code), I'm leaving it in. It may come in - handy at some later date. - -1998-09-18 Jim Kingdon <kingdon@pennington.cyclic.com> - - * version.c: Advance version number to 1.10.2.1. - - * Version 1.10.2. - -1998-09-13 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c: Refuse to Copy-file to another directory - * sanity.sh (client): New test, tests for this. - - * edit.c (editors_fileproc), watch.c (watchers_fileproc): Use - cvs_output rather than writing to stdout. - * sanity.sh (devcom): Use dotest for tests 178, 180, and 183 - (tests that we preserve existing behavior on "cvs editors"). - - * commit.c (check_fileproc): Don't allow commits in Emptydir. - * sanity.sh (emptydir-8): Test for this change in behavior. - - * sanity.sh: Add some compatibility tests to TODO comments at end. - -1998-09-10 Jim Kingdon <kingdon@harvey.cyclic.com> - - * wrapper.c (wrap_add): Remove obsolete comment about -m. - - * server.c (server_updated): Check for error from CVS_UNLINK. - -1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (serve_root): Allocate with malloc, not xmalloc. - - * root.c (set_local_cvsroot): Move memory allocation from here... - * server.c (serve_root): ...to here. Fixes error handling. - - * root.c (parse_cvsroot): Don't call check_root_consistent; - parse_cvsroot is only used for local and client. - * root.c (set_local_cvsroot): Move check_root_consistent - functionality from here... - * server.c (serve_root): ...to here. Fixes error handling. Also - made the error more explicit, while I am at it. - * server.c (Pserver_Repos): Now static. - * cvs.h: Don't declare it. - * root.c (check_root_consistent): Removed; no longer needed. - * sanity.sh (pserver): New test, tests for this behavior and some - other basic pserver stuff. - - * update.c (merge_file): Use cvs_output for "already contains the - differences" message. Found this one when I actually observed the - out-of-order bug in Real Life(TM). - -1998-09-09 Jim Kingdon - - * find_names.c (find_dirs): Make sure to zero errno before - going around the loop again. - * find_names.c (find_rcs): Make sure to set save_errno. - (thanks to Alexandre Parenteau for reporting both problems). - -1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com> and Michael Pakovic - - * edit.c (notify_do): Only free line if it is not NULL. - -1998-09-07 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h: dirs_sent_to_server should not be inside - AUTH_SERVER_SUPPORT (reported by both Richard Levitte and Murray - Bishop, thanks). - - * lock.c, cvs.h: New variable lock_dir. - * parseinfo.c (parse_config): New option LockDir. - * lock.c (lock_name): New function, abstracts out lock file naming - and also supports LockDir. - * lock.c (lock_simple_remove, Reader_Lock, write_lock, set_lock): - Call it (6 places, to create/remove read/write/master locks). - (Lock_Cleanup): Refuse to reenter this function. - * sanity.sh (lockfiles): New test, tests for this feature. - -1998-09-03 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (multiroot): Expect ${TESTDIR} in output instead of - assuming it is /tmp/cvs-sanity (thanks to Mark D. Baushke of Cisco). - Clean up working directory when done (fixes apparent thinko). - - * server.c (create_adm_p): Fix one "return" which didn't return a - value. - (dirswitch): Check for errors from create_adm_p. - - * sanity.sh: Set LC_ALL rather than just LC_COLLATE. - -Wed Sep 2 02:30:22 1998 Jim Kingdon <kingdon@pennington.cyclic.com> - - * version.c: Bump version number to 1.10.1.1. - - * Version 1.10.1. - -1998-09-01 Jim Kingdon <kingdon@harvey.cyclic.com> - - Administrative note regarding Noel's changes to allow one to - switch from one CVS root to another in a single command: The - ChangeLog entries for the changes which Noel just checked in - appear for 1998-09-01, 1998-08-28, 1998-08-25, 1998-08-19, and - 1998-08-18, rather than being all together. - - * main.c (set_root_directory): Fix whitespace. - (main): Nuke new -m option and just have that message controlled - by -t. - * server.c (server): Revert the CVS_SERVER_SLEEP code back the way - it was in CVS 1.10. Attaching to the parent process is relatively - boring (you can just run "cvs server" under a debugger instead), - but connecting to the child process is what the old code was for. - * recurse.c, server.c: Remove DEBUG_NJC code. - -1998-09-01 Noel Cragg <noel@swish.red-bean.com> - - * server.c (do_cvs_command): add another environment variable, - CVS_SERVER_SLEEP2, after forking to pause the program so one can - attach a debugger. - - * sanity.sh (crerepos): clean up crerepos-18 now that multiroot - works in this case. - (multiroot): finalize tests for local vs. remote operation. - - * recurse.c (start_recursion): near the beginning, save the list - of directories to spoof as command-line arguments, if necessary. - Use that list near the end and call send_file_names to send those - arguments to the server. - (do_argument_proc): removed, since we call send_file_names now. - - * main.c (main): re-initialize dirs_sent_to_server on each pass - through the loop for each CVSROOT. - - * cvs.h: add proto for global variable which keeps track of which - directories have been sent to the server when in client mode. - - * client.c (is_arg_a_parent_or_listed_dir): new function. - (arg_should_not_be_sent_to_server): new function. Tries to decide - whether the given argument should be sent to the server, based on - the current CVSROOT and the list of directories sent to the - server. - (send_repository): add the directory name to the list of - directories sent to the server. - (send_file_names): call arg_should_not_be_sent_to_server. - - * add.c (add): switch the order of send_files and send_file_names - to make multiple repository support possible. send_files needs to - create a list of directories being requested so that - send_file_names can decide which command-line arguments to send to - the server for the given current CVSROOT. - * admin.c (admin): same. - * commit.c (commit): same. - * diff.c (diff): same. - * edit.c (editors): same. - * log.c (cvslog): same. - * rcs.c (annotate): same. - * remove.c (cvsremove): same. - * status.c (cvsstatus): same. - * tag.c (cvstag): same. - * update.c (update): same. - * watch.c (watch_addremove): same. - (watchers): same. - -1998-08-31 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Remove "debug" function; it was apparently checked - in accidentally by Norbert Kiesel's change. - -1998-08-31 Norbert Kiesel <nk@iname.com> - - * release.c (release): modify last patch to release so that - save_cwd is called only once and restore_cwd is always called when - neccessary. Also fixed a tiny memory leak. - - * sanity.sh (release): added some more tests for "cvs release" - including a test with two dirs and a "no" for the first one (which - fails without the above patch). - -1998-08-28 Noel Cragg <noel@swish.red-bean.com> - - * sanity.sh (crerepos-18): add new comment and change test - slightly to support multiroot. - (multiroot): add more tests. - - * server.c (create_adm_p): new function. - (dirswitch): call create_adm_p. Modify the code to always write a - new CVSADM_REP file, since create_adm_p might have put a - placeholder there and our value is guaranteed to be correct. - (server): move the CVS_SERVER_SLEEP check here so we can debug - things at an earlier stage. - - * recurse.c (start_recursion): add large comment about the ideal - solution to the "Argument xxx" problem. - - * main.c (main): move position of debugging comment for -m flag. - - * diff.c (diff): clear a static variable. - - * client.c (send_file_names): check to see if we should send this - argument to the server based on the contents of the appropriate - CVSADM directory. This avoids "nothing known about foo" messages - and problems with duplicate modules names in multiple - repositories. - (send_a_repository): change method of calculating toplevel_repos - to support multiple CVSROOTs. - (start_server): clear some static variables. - -1998-08-28 Jim Meyering <meyering@ascend.com> - - * sanity.sh (basicc-8, basicc-11): Use `.*' instead of explicit - `Operation not permitted'. Solaris2.5.1 gets a different error: - `Invalid argument'. - -1998-08-26 Eric M. Hopper - - * sanity.sh: Set LC_COLLATE to "C". - -1998-08-25 Noel Cragg <noel@swish.red-bean.com> - - * sanity.sh (multiroot): new set of tests to check the behavior of - multiroot. - - * diff.c (diff): set options value to NULL after freeing to reset - the state for the next time around. - -1998-08-25 Jim Kingdon <kingdon@harvey.cyclic.com> - - Fix problems with trying to rename an open file: - * rcs.c, rcs.h (RCS_setattic): New function. - * commit.c (remove_file, checkaddfile): Call it. - -1998-08-24 Jim Kingdon <kingdon@harvey.cyclic.com> - - * release.c (release): Use save_cwd and restore_cwd to get back to - where we started, rather than hoping that CVS_CHDIR ("..") will do - something useful. This removes the need for most of - release_delete, so remove that function and inline what is left. - * sanity.sh (basicc): Adjust tests for this fix, also some tests - with multiple arguments to "cvs release" (in the non-"-d"-case, it - would seem like the old code would CVS_CHDIR into directories and not - CVS_CHDIR back, but I'm not going to investigate this and it - should be a moot point with this fix.). - - * sanity.sh (basicc): Add tests for a serious bug in "cvs release - -d .". - - More error handling fixes: - * ignore.c (ignore_files): Check for errors from opendir and - readdir. - * find_names.c (Find_Names): Check for errors from find_rcs. - (find_rcs, find_dirs): Comment error handling better; also return - an error if we got one from readdir. - * filesubr.c (deep_remove_dir): Also check for errors from readdir. - * import.c (import_descend): Print message on error from opendir - or readdir. - * commit.c (remove_file): Check for errors from CVS_MKDIR and - CVS_RENAME. - (remove_file): No need to remove the file in the temporary - directory; server.c now informs time_stamp_server of what is going - on via CVS/Entries rather than a file with a kludged up timestamp. - * client.c, entries.c, login.c, logmsg.c, mkmodules.c, patch.c, - remove.c, update.c: Check for errors from unlink_file. - * mkmodules.c (write_dbmfile, rename_dbfile, rename_rcsfile): - Check for errors from fclose, CVS_RENAME, and CVS_STAT. - * mkmodules.c (checkout_file): Clarify error handling convention. - * mkmodules.c (mkmodules): Call checkout_file accordingly. - * entries.c (Entries_Open): Check for errors from fclose. - -1998-08-21 Ian Lance Taylor <ian@cygnus.com> - - * import.c (import): Output suggested merge command using - cvs_output_tagged rather than just cvs_output. Don't put - CVSroot_cmdline in the log file. - * client.c (importmergecmd): New static struct. - (handle_mt): Handle +importmergecmd tag. - * sanity.sh (import): Use an explicit -d in importb-2, to test - whether it is reported in the suggested merge command. - -1998-08-20 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh (import): Rewrite tests to use dotest. - -1998-08-20 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Add comments about binary files and cvs import. - -1998-08-19 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (importc): Use ${username} in one place where I had - missed it. - - Make import -d work client/server: - * client.c, client.h (client_process_import_file): Take new - argument, for whether -d is specified, and send Checkin-time - request if it is set. - * import.c (import_descend): Pass it. - * main.c, cvs.h (date_to_internet): New function. - * server.c (server_modtime): Call date_to_internet. - * server.c (serve_checkin_time): New function. - (requests): Add "Checkin-time" request. - (serve_modified): If it was sent, set the timestamp in the - temporary directory. - * import.c (import): If the client sends a -d option, complain. - (import): For the server, always use the timestamps from the temp - directory. - (import): Don't send a -d option to the server. - * sanity.sh (importc): Add tests for import -d. - -Wed Aug 19 15:19:13 1998 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (unedit-without-baserev-5): use ${DOTSTAR} instead - of .* since we expect to match multiple lines. - -1998-08-19 Ian Lance Taylor <ian@cygnus.com> - - * cvs.h (CVSroot_cmdline): Declare. - * root.c (CVSroot_cmdline): Define. - * main.c (main): Set CVSroot_cmdline if the -d option is used. - * import.c (import): If CVSroot_cmdline is not NULL, then mention - an explicit -d option in the suggested merge command line. - -Wed Aug 19 00:28:50 1998 Noel Cragg <noel@swish.red-bean.com> - - * recurse.c (do_dir_proc): don't muck with CVS/Root directories - when running in server mode. - (do_recursion): same. - - * main.c (main): add the command-line option `m' to help debug the - multiroot environment; it prints out the value of CVSROOT for each - iteration through the main loop. Also, changed the main loop so - that it gets executed only once when running in server mode (the - server will only deal with a single CVSROOT). - - * recurse.c (do_recursion): change default for - PROCESS_THIS_DIRECTORY to true; we should always process a - directory's contents unless there's an existing CVS/Root file with - a different root than the current root to tell us otherwise. - (do_dir_proc): same. - -Tue Aug 18 14:30:59 1998 Noel Cragg <noel@swish.red-bean.com> - - * recurse.c (do_recursion): check the current value of CVS/Root - and add it to our list of CVSROOTs if it doesn't exist. Decide - whether or not to process files in this directory based based on - the value of CURRENT_ROOT. - (do_dir_proc): same. - - * main.c: add two new globals -- root_directories and current_root - -- which keep track of the values of CVSROOT we've seen and which - value of CVSROOT we're currently processing. - (main): put the main loop for stepping through cvsroot values - here, since we might need to send command-specific arguments for - every unique non-local cvsroot. Moved blocks of code around so - that one-time initializations happen first (outside the loop) and - the other stuff happens inside the loop. - (set_root_directory): helper function. - - * cvs.h: add prototypes for root_directories and current_root, two - new globals for keeping track of multiple CVSROOT information. - -1998-08-18 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Don't assume that the shell leaves $^ unexpanded in - an unquoted here-document (suggested by Bart Schaefer to help when - zsh is the shell). - -1998-08-17 Ian Lance Taylor <ian@cygnus.com> - - * commit.c (checkaddfile): Don't call fix_rcs_modes. - (fix_rcs_modes): Remove. - -1998-08-16 Jim Kingdon <kingdon@harvey.cyclic.com> - - * create_adm.c (Create_Admin): Don't condition traces on - SERVER_SUPPORT; SERVER_SUPPORT shouldn't do (much of) anything - independent of server_active. - - * sanity.sh (binfiles3): New test, for yet another binary file - bug (sigh). Thanks to Jason Aten for reporting this one. - -1998-08-15 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcscmds.c (call_diff_write_output): Update to reflect new - calling convention for the write_output callback. - -1998-08-15 Jim Meyering <meyering@ascend.com> - - * update.c (merge_file): Warn about failed unlink when not due - to ENOENT. - - * server.h (CLIENT_SERVER_STR): New macro - * create_adm.c (Create_Admin): Use it. - * entries.c (Scratch_Entry, Register): Use it. - * filesubr.c (copy_file, xchmod, rename_file, unlink_file): Use it. - * history.c (history_write): Use it. - * modules.c (do_module): Use it. - * no_diff.c (No_Difference): Use it. - * run.c (run_popen): Use it. - * server.c (server_register): Use it. - -1998-08-14 Jim Meyering <meyering@ascend.com> - - * hardlink.c (lookup_file_by_inode): Use existence_error rather than - comparing errno to ENOENT directly. - - * client.c (copy_a_file): Unlink destination before doing copy. - * sanity.sh (join-readonly-conflict): New test for this -- it would - fail only in client/server mode. - - * sanity.sh (rcsmerge-symlink-4): Don't use `test -L', it's not - portable. Instead, match against the output of `ls -l'. - (dotest tag8k-16): Simplify tag-construction code and at the same - time, avoid using expr's `length' and `substr' operators. Not - all versions of expr support those. - -1998-08-14 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Bump version number to 1.10.0.1. - -Thu Aug 13 11:15:24 1998 Noel Cragg <noel@swish.red-bean.com> - - * version.c: Change version number to 1.10 and name to `Halibut'. - - * sanity.sh (rcslib): new tests to check behavior of symlinks in - the repository. - -Wed Aug 12 15:39:38 1998 Noel Cragg <noel@swish.red-bean.com> - - * main.c (lookup_command_attribute): the `annotate' command - shouldn't require access to the repository. Add comment about - commands that do not use the working directory. - -Mon Aug 10 10:26:38 1998 Noel Cragg <noel@swish.red-bean.com> - - * version.c: Change version number to 1.9.30. - -Thu Aug 6 17:44:50 1998 Noel Cragg <noel@swish.red-bean.com> - - * server.c (serve_rdiff): change the name of the command (for - error reporting, etc.) from "patch" to "rdiff." - (serve_remove): rename from "cvsremove" to "remove." - - * main.c (lookup_command_attribute): the `rdiff' command shouldn't - require write access to the repository. - -1998-08-06 David Masterson of kla-tencor.com - and Jim Kingdon - - * commit.c (commit_filesdoneproc): Don't call strlen ("CVSROOT") - from within the assert statement. Apparently HP's cc compiler on - HPUX 10.20 has trouble with that. - -1998-08-06 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_checkin): When adding branch, if there is a lock on - the branchpoint owned by someone else, leave it alone. This - restores CVS 1.9 (RCS 5.7) behavior, fixing a core dump. - * sanity.sh (reserved): New tests reserved-16 through reserved-19 - test for this fix. - -1998-08-05 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (unedit-without-baserev): Use ${QUESTION} not "?". - This makes it work with GNU expr 1.12 as well as 1.16. - -Sun Aug 2 20:27:44 1998 Noel Cragg <noel@swish.red-bean.com> - - * mkmodules.c: add comment about TopLevelAdmin for the initial - contents of CVSROOT/config. - -1998-07-29 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_checkin): Only try to call xreadlink if HAVE_READLINK - is defined. - -Tue Jul 28 19:33:08 1998 Noel Cragg <noel@swish.red-bean.com> - - * version.c: Change version number to 1.9.29. - - * rcs.c (RCS_checkin): add code to follow symbolic links in the - repository. - -Sun Jul 26 05:14:41 1998 Noel Cragg <noel@swish.red-bean.com> - - * This set of changes reverts the code to pre-1.9.2 behavior and - does not create CVS directories at top-level (except for the - obvious "cvs co ."). Added a new configuration option to switch - between 1.9 and 1.9.2 behavior. - - * recurse.c (do_argument_proc): new function. - (start_recursion): in the case that we've done a command from - top-level but have no CVS directory there, the behavior should be - the same as "cvs <cmd> dir1 dir2 dir3...". Make sure that the - appropriate "Argument" commands are sent to the server by calling - walklist with do_argument_proc. - - * client.c (call_in_directory): only create the top-level CVS - directory when we're checking out "." explicitly. The server will - force creation of this directory in all other cases. - - * checkout.c (checkout_proc): only generate the top-level - directory when the TopLevelAdmin=yes. Also send a message to the - client to do the same. - - * parseinfo.c (parse_config): handle TopLevelAdmin option. Set - top_level_admin. - - * main.c: add new variable top_level_admin. - * cvs.h: add extern definition for above. - - * sanity.sh: since we're reverting to pre 1.9.2 behavior for - top-level CVS directories, I needed to make changes to a bunch of - tests that made assumptions about said directories. - (preamble): make sure to add read and execute access to everything - in TMPDIR before removing, since some tests make things read-only. - (basicb-1a, basicb-1b, basicb-9a, basicb-9b): use dotest_fail - because these tests check for the non-existant top-level CVS - directory. - (basicc-3, emptydir-6, emptydir-7, crerepos-6): use "rm -rf" so it - won't complain when trying to remove the non-existant top-level - CVS directory. - (106.5): remove imported-f2-orig.tmp. - (modules2-10, emptydir-4, abspath-1ba, abspath-1bb): cd into the - directory where files exist before using the "add" command so cvs - can find CVSROOT in CVS/Root. - (cvsadm-2): look at a different CVS/Repository file, since the - top-level one doesn't exist. - (taginfo-3): create the directory in the repository directly - rather than relying on the fact that the top-level CVS directory - was created in a previous test. - (serverpatch-6): update first-dir explicity, rather than relying - on the non-existant top-level CVS/Entries file. - (crerepos-18): look at CVS/Repository in a subdirectory rather - than in the non-existant top-level CVS directory. - (toplevel): add code to set TopLevelAdmin=yes. - (toplevel2): new tests -- same as toplevel, but TopLevelAdmin=no. - -1998-07-21 Jim Meyering <meyering@ascend.com> - - * rcs.c (RCS_checkout): Hoist frees of rev and value. - Warn and return 1 in several cases rather than exiting via - `error (1, ...'. The latter could abort a multi-file commit - in mid-stream, leaving stale locks in the repository. - -1998-07-16 Jim Kingdon <kingdon@harvey.cyclic.com> - - * build_src.com (rcscmds.c): Also look for include files in - [-.diff], just like Ian's 1998-06-18 change to Makefile.in - -1998-07-14 Jim Kingdon <kingdon@harvey.cyclic.com> - - * tag.c (pretag_proc), rtag.c (pretag_proc): Don't pass RUN_REALLY - to run_exec. This means that taginfo does not get executed if the - global -n option is specified. Which makes it like loginfo, -i, - -e, -o, -t, -u in modules, editinfo, and verifymsg and unlike - commitinfo. The old behavior was pretty bad in the sense that it - doesn't provide any way to log only the tags which actually - happen. - * sanity.sh (taginfo): New tests taginfo-11 to taginfo-13, for this. - -1998-07-12 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (ann-id): Write the test so that it tests for the - current (buggy) behavior. - - * sanity.sh (taginfo): Also clean up cvsroot/first-dir. - -1998-07-12 Jim Meyering <meyering@ascend.com> - - * sanity.sh (ann-id): New (currently failing) test for bug in how - rcs keywords are expanded in the output of `cvs annotate'. - -1998-07-12 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (taginfo): Write the TESTDIR into the script rather - than having the script look at the environment. This means that - it will work if TESTDIR is set by sanity.sh as well as if - sanity.sh finds TESTDIR in the environment. - -1998-07-11 Jim Kingdon <kingdon@harvey.cyclic.com> - - * tag.c (check_fileproc): Calculate the revision to be tagged the - same way that tag_fileproc does. - * sanity.sh (taginfo): New tests, test for this (before this fix, - brtag had said 1.1 not 1.1.2.1). - -1998-07-10 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (unedit-without-baserev): Also clean up "2" directory. - -1998-07-08 Jim Kingdon <kingdon@harvey.cyclic.com> - - * edit.c (unedit_fileproc): If the Baserev file is missing, don't - get the working file from CVS/Base. The previous code could get - you version 1.1 of the working file and put 1.2 in CVS/Entries. - * sanity.sh (unedit-without-baserev): New tests test for this. - -1998-07-02 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (unedit-without-baserev): Move the test itself to be - in the same order as in the "tests" variable. - -1998-07-02 Ian Lance Taylor <ian@cygnus.com> - - * rcscmds.c: Don't include <stdarg.h> or <vasprintf.h>. Don't - declare vasprintf. - (call_diff_printf_output): Remove. - (call_diff_stdout_callbacks): Don't initialize printf_output - field--it has been removed from the interface. - (call_diff_file_callbacks): Likewise. - -1998-07-01 Jim Meyering <meyering@ascend.com> - - * edit.c (unedit_fileproc): Handle the case in which base_get - returns a NULL baserev. That happens when a file being `unedit'ed - exists in the CVS/Base directory, but isn't listed in the CVS/Baserev - file. The one case I've seen had no Baserev file at all. The symptom - (if you're lucky) is a segmentation fault upon unedit. If you use - SunOS4.1.4 for which printf prints NULL pointers as `(null)', your - unedit command will complete normally, but it will have corrupted - your CVS/Entries file and a subsequent update may result in an - assertion failure, a core dump, and a stale lock in the repository. - * sanity.sh (unedit-without-baserev): New test for this. - -1998-07-01 Andy Mortimer of aeat.co.uk - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (server_updated): Use a prototype if we are using them - for declarations. - -1998-06-29 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (commit-readonly): Protect keyword against expansion - in sanity.sh itself. Keep the keyword in the file which we check - in (or else this fails to test for the RCS_checkout change). - -1998-06-27 Jim Meyering <meyering@ascend.com> - - * rcs.c (RCS_checkout): If opening the local workfile fails due to - lack of write access, try to chmod the file and retry the open. - Before, a commit could fail part way through merely because the - open to rewrite with newly expanded rcs keywords would fail. It's - easy to make this happen if you use `cvs -r' or CVSREAD and you - apply a patch to one of your read-only source files -- patch - preserves the read-only setting for the file and your next commit - will fail after committing that file, but before rewriting - (checking out) your working copy. - * sanity.sh (commit-readonly): New test for this. - -1998-06-25 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (patch_file): Update comments regarding context diffs - to reflect diff library. - -1998-06-23 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (modules4): Add tests for reversing the order of the - "!first-dir/sdir" and "first-dir". - -1998-06-23 Jim Kingdon <kingdon@harvey.cyclic.com> - and Dave Wolfe@Motorola. - - * sanity.sh (modes2): Touch the file before chmod'ing it. - -1998-06-21 Ian Lance Taylor <ian@cygnus.com> - - * update.c (merge_files): Revert changes of 1998-06-19. Instead, - register a merged file with a dummy time stamp. Only set - last_register_time if we need to. - (join_file): Likewise. Always register a merged file, not just - when the merge fails. - -1998-06-21 Jim Kingdon <kingdon@harvey.cyclic.com> - - * call_diff_write_output, call_diff_printf_output, - call_diff_flush_output, call_diff_write_stdout, call_diff_error, - call_diff_stdout_callbacks, call_diff_file_callbacks): Re-indent. - -1998-06-19 Ian Lance Taylor <ian@cygnus.com> - - * update.c (merge_file): Make sure the time stamp of the file is - different from the time stamp we register in the Entries file. - (join_file): Likewise. - -1998-06-18 Ian Lance Taylor <ian@cygnus.com> - - * rcscmds.c: Include <stdio.h>. Include either <stdarg.h> or - <varargs.h>. Declare vasprintf. - (call_diff_write_output): New static function. - (call_diff_printf_output): New static function. - (call_diff_flush_output): New static function. - (call_diff_write_stdout): New static function. - (call_diff_error): New static function. - (call_diff_stdout_callbacks): New static variable. - (call_diff_file_callbacks): New static variable. - (call_diff): Don't sleep. Use a callback structure when calling - the diff library. - (call_diff3): Likewise. - - * rcscmds.c: Include diffrun.h. - (call_diff, call_diff3): Pass NULL callback parameter. - (diff_run, diff3_run): Don't declare. - * Makefile.in (rcscmds.o): New target, to use -I for diff - directory. - (zlib.o): Depend upon zlib.h. - -1998-06-09 Mike Sutton@SAIC - - Make it compile with Sun's bundled K&R C compiler: - * rcs.c (count_delta_actions): Change to static to match - declaration. - * client.c (handle_wrapper_rcs_option): Rename error label to - handle_error to avoid clash with function name. - -1998-06-09 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_delete_revs): If we are trying to delete all - revisions, give an error rather than assertion failed. - * sanity.sh (basicb): New tests basicb-o* test for this. - -1998-06-04 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add): Only send "Directory" requests if we need to. - -1998-06-02 Assar Westerlund <assar@sics.se> - - * client.c: Check for HAVE_GSS_C_NT_HOSTBASED_SERVICE rather than - assuming that GSS_C_NT_HOSTBASED_SERVICE is a macro. - * server.c: Likewise. - -1998-06-02 Jim Kingdon <kingdon@harvey.cyclic.com> - - * fileattr.c (fileattr_read): Check for NULL return from strchr. - * sanity.sh (devcom3): New test devcom3-10 checks for this. - -1998-06-01 Assar Westerlund <assar@sics.se> - and Ian Lance Taylor <ian@cygnus.com> - - * client.c: If HAVE_GSSAPI_H, include <gssapi.h>. Only include - <gssapi/gssapi.h> if HAVE_GSSAPI_GSSAPI_H. Only include - <gssapi/gssapi_generic.h> if HAVE_GSSAPI_GSSAPI_GENERIC_H. - (GSS_C_NT_HOSTBASED_SERVICE): Define if not defined. - (connect_to_gserver): Use GSS_C_NT_HOSTBASED_SERVICE instead of - gss_nt_service_name. - * server.c: Same header file changes. - (GSS_C_NT_HOSTBASED_SERVICE): Define if not defined. - (gserver_authenticate_connection): Use GSS_C_NT_HOSTBASED_SERVICE - instead of gss_nt_service_name. - -1998-06-01 Jim Meyering <meyering@ascend.com> - - * sanity.sh (tag8k): Add a test for the 1998-05-02 rcs.c bug fix. - -1998-05-26 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (annotate): Call tag_check_valid like the other functions - which have a -r option. - * sanity.sh (ann): New test ann-14 tests for this. - -1998-05-24 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (importc): New tests importc-5 through importc-8 test - for a (fairly obscure) regression from CVS 1.9. - -1998-05-23 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (modules2): Add comment listing cvs release tests. - (info): New test info-cleanup-0 tests "cvs -n release". - - * rcs.c (rcsbuf_getid): Remove semicolon at end of #undef. I'm - kind of surprised that compilers accepted this at all, but - removing it squelches a warning for some compilers. - - * version.c: Change version number to 1.9.28.1. - - * Version 1.9.28. - -1998-05-22 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_cmp_file): Check for errors from CVS_FOPEN. This - restores the CVS 1.9 behavior (fatal error if we can't open the - file), and corrects an apparent oversight in Ian's 13 Apr 1997 - change. - * sanity.sh (modes2): New test, tests for this. - -1998-05-22 Ian Lance Taylor <ian@cygnus.com> - - * server.c (server_updated): Correct test for whether to unlink - the file. - -1998-05-20 Jim Kingdon <kingdon@harvey.cyclic.com> - - * wrapper.c (wrap_add): Disable -t/-f wrappers at least until the - serious bug can be fixed. - -1998-05-15 Jim Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (checkout): Call server_pathname_check on the - argument to "cvs co -d". - * server.c (server_pathname_check): Add comment about how we could - be handling absolute pathnames. - * sanity.sh (abspath): Rewrite the tests which run "cvs co -d /foo" - for remote, to reflect this. - - * sanity.sh (abspath): Also do the "cannot rename" work-around for - abspath-7d. - -1998-05-13 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (commit_filesdoneproc): Free admin_dir when done with it. - -1998-05-13 Jim Meyering <meyering@ascend.com> - - * sanity.sh (editor): Change bogus sed command, `s/^/x&/g', to `s/^/x/'. - The former exercised a bug in GNU sed-3.01-beta3. - (emptydir-8): Add `Rebuilding administrative file database' message, - since now it does that. - * commit.c (commit_filesdoneproc): Pass only the admin directory - pathname to mkmodules. - Remove #if 0, now that it's fixed. - - * status.c (cvsstatus): Rename from `status' to avoid shadowing - lots of locals and parameters by the same name. - * server.c (serve_status): Update caller. - * main.c (cmds[]): Update table entry. - * cvs.h: Update prototype. - - * commit.c (commit_filesdoneproc): Remove trailing blanks. - (commit) [CLIENT_SUPPORT]: Remove unnecessary (and local-shadowing) - declaration of `err'. - Rename global `tag' to `saved_tag' to avoid overshadowing `tag' - parameters of three functions. - Rename global `message' to `saved_message' to avoid overshadowing - `message' parameter of a function. - Rename global `ulist' to `saved_ulist' and move dcl up with others. - -1998-05-12 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (commit_filesdoneproc): #if 0 the new code until it can - be fixed. - - * commit.c (commit_filesdoneproc): Add comment explaining last - change. - -1998-05-12 Jim Meyering <meyering@ascend.com> - - * commit.c (commit_filesdoneproc): Call mkmodules not just when - committing a file directly under CVSROOT, but also when committing - files in subdirectories of CVSROOT. - -1998-05-08 Jim Meyering <meyering@ascend.com> - - * filesubr.c (xreadlink): NUL-terminate the symbolic link name. - Use a much smaller initial buffer length. - Test errno only if readlink fails. - Use xstrdup then free the original link name so we don't waste space. - -1998-05-02 Jim Meyering <meyering@ascend.com> - - * rcs.c (rcsbuf_getword): Fix off-by-one error that would result in - an abort (the first one in rcsbuf_getkey) when operating on on some - ,v files with over 8192 bytes of tag and branch info. - -1998-05-04 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (ann): New tests ann-12 and ann-13 test for specifying - a numeric branch. - -1998-05-02 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c: Add comments about getting rid of rcsbuf_getid, - rcsbuf_getword, and rcsbuf_getstring. - - * sanity.sh (abspath): Revise the workarounds to deal with exit - status. - -1998-04-30 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (abspath): Work around the "cannot rename" bug. - -1998-04-27 Jim Kingdon <kingdon@harvey.cyclic.com> - - * classify.c (Classify_File): Add comments about checking whether - command name is "update". - -1998-04-22 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version number to 1.9.27.1. - - * Version 1.9.27. - -1998-04-20 Jim Kingdon <kingdon@harvey.cyclic.com> - - (This diff was run by devel-cvs and everyone seemed to like it). - * diff.c (diff_file_nodiff): Make HEAD mean the head of the branch - which contains the sticky tag, not the sticky tag itself. - * rcs.c, rcs.h (RCS_branch_head): New function. - * sanity.sh (head): Update for this changed behavior. - -1998-04-19 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Move emptydir tests from basicb to new test emptydir. - This is because we now need a module definition to create Emptydir; - "co -d" doesn't cut it anymore. - -1998-04-17 Petri Virkkula - - * server.c (mkdir_p): Ignore EROFS error (like for EACCES). - -1998-04-16 Jim Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (checkout_proc): Don't create directories above the - last one specified in "co -d". - (build_dirs_and_chdir): Revert Noel's change of 17 Feb 1998. - (struct dir_to_build): New field just_chdir. - (build_dirs_and_chdir): Test it. - * sanity.sh (abspath): New tests abspath-7* test for a bug which - we fix, in which CVS would create bogus "D/////" entries in - CVS/Entries. - (abspath): Revise abspath-3* tests to test for the fact that we no - longer create directories above the last one specified in "co -d". - I checked that CVS 1.9 gives an error on this, so changing this - behavior back should be OK. - (cvsadm-2d3): Likewise (also checked CVS 1.9 for this case). - (cvsadm-2d3d): Likewise (also checked CVS 1.9 for this case). - (cvsadm-2d{4,5,6,7,8}, cvsadm-N2d{3,4,5,6,7,8}): Adjust for new - behavior (same case as cvsadm-2d3). - (cvsadm-2d{4,5,6,7,8}d, cvsadm-N2d{3,4,5,6,7,8}d): Remove test - (same case as cvsadm-2d3d). - (cvsadm): For remote, skip most these tests. - (abspath): When cleaning up, delete mod1 and mod2 rather than mod1 - twice (longstanding bug, apparently only becomes visible if you - run the tests in a certain order). - -1998-04-14 Wilfredo Sanchez <wsanchez@apple.com> - - * rcs.c: variable "lockfile" was being referenced after being - free'd. Bad. Moved the free() call down. - -1998-04-12 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (rcs): Add test for annotate and the year 2000. - - * server.c (do_cvs_command): If there are partial lines left when - the child process is done, send them along. - * sanity.sh (rcs, rcs2): Enable all tests for remote; tests for - this fix. - -1998-04-11 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (client_senddate): Pass SDATEFORM not DATEFORM to - sscanf. This fixes a Y2K bug. - - * history.c (history, select_hrec): Change since_date from time_t - to RCS format. Use the usual machinery (in particular, Make_Date - and client_senddate) so that it will work on VMS too. - * main.c, cvs.h (date_from_time_t): New function. - * sanity.sh (history): New test, to test that this didn't break - anything (also tests client_senddate fix). - -1998-04-11 Norbert Kiesel <nk@iname.com> - - * server.c (cvs_output_binary): Shut up "gcc -Wall" by removing - unnecessary else if test. - * server.c (check_password): Fix uninitialized memory read if - shadow passwords are used. Also added some comments. - * rcs.c (RCS_checkout): Make sure to call chown with -1 for uid or - gid if they should not be changed - -1998-04-10 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (rcs2): New test, tests for various Y2K cases. - * rcs.c (getdelta): Value for "state" keyword is optional (bug - discovered incidentally in writing rcs2 test). - -1998-04-09 Jim Kingdon <kingdon@harvey.cyclic.com> - - * filesubr.c, cvs.h (link_file): Remove; no longer used. - -1998-04-08 Jim Kingdon <kingdon@harvey.cyclic.com> - - * recurse.c (do_dir_proc): Restore update_dir rather than a - computation which appears to, but does not necessarily, restore it - (reported by various people; this fix is from Greg Hudson). - * sanity.sh (importc): New test, tests for this fix. - -1998-03-27 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_lock): If the revision is already locked, give an - error rather than dumping core. - * sanity.sh (reserved): New test reserved-13c tests for this. - -1998-03-25 Loren J. Rittle - - * import.c (add_rev): Rewrite to use RCS_FLAGS_KEEPFILE option - of RCS_checkin() to avoid damage to imported files instead of - externally undoing damage after the fact. The side effect is - that callers of add_rev() may now incrementally walk the - entries of the current directory without seeing gratuitous - changes to the directory structure (under at least one file - system under at least one OS). - -1998-03-18 Jim Kingdon <kingdon@harvey.cyclic.com> - - * error.c (error): Save and restore errno. Should fix test case - conflicts3-23 on SCO 5.0.2. Reported by Steve Cameron. - - * sanity.sh (admin): Rename admin-26-o* to admin-26-*; the "o" - stands for "cvs admin -o". Add comment about length of tests. - Use ${PLUS}. - -1998-03-05 Dan Wilder <dan@gasboy.com> - - * Fix problem with cvs admin in which -ntag:branch - option associated tag with the branch's head revision. - Should have used branch number. Entailed in this fix, - the following. - - * Add new functions "RCS_exist_rev", "RCS_exist_tag", - "RCS_tag2rev", and "RCS_valid_rev" to rcs.c. RCS_tag2rev - is similar to RCS_gettag, but does less interpretation. - - * Plug a small memory leak. - - * Add tests admin-26 through admin-29 to sanity.sh, - to test "cvs admin -n". - -1998-03-17 Samuel Tardieu <sam@inf.enst.fr> - - * server.c (server_register): protect dereferencing timestamp in - the trace message when it is null, to avoid a segmentation fault. - -1998-03-16 Jim Kingdon <kingdon@harvey.cyclic.com> - - * options.h.in (MY_NDBM): Rewrite the comment explaining this - option. It was not clear to everyone who "my" referred to, for - example. - - * hardlink.c (list_linked_files_on_disk): Remove unused variables - err and p. - (list_linked_files_on_disk): Add comment about memory allocation - of return value. - * rcs.c (rcsbuf_getword): Shut up gcc -Wall with a "return 0". - (RCS_checkin): Remove unused variable fullpath. - * sanity.sh (hardlinks): Remove comment about spurious warnings; - the warnings are gone. - -1998-03-12 Tim Pierce <twp@skepsis.com> - - New functions for parsing and writing hardlink fields. - * rcs.c [PRESERVE_PERMISSIONS_SUPPORT] (puthardlink_proc): New - function. - (putdelta) [PRESERVE_PERMISSIONS_SUPPORT]: Use it. - (rcsbuf_getid, rcsbuf_getstring, rcsbuf_getword): New functions. - (getdelta): Call them, storing `hardlinks' field in vnode->hardlinks. - (RCS_reparsercsfile): When setting rdata->desc, xstrdup value - rather than rcsbuf_valcopying it (due to changes in how getdelta - handles keys and values in newphrases). - - * sanity.sh (hardlinks): Use uglier filenames. Checking out - hardlinked files no longer produces the same spurious diagnostics, - so fix that test. - (hardlinks-2.3): Renamed from hardlinks-2.2 (duplicate test name). - - New infrastructure for managing hardlink lists internally... - * hardlink.c, hardlink.h (list_linked_files_on_disk, - compare_linkage_lists, find_checkedout_proc): New functions. - * rcs.h (struct rcsversnode) [PRESERVE_PERMISSIONS_SUPPORT]: New - member `hardlinks'. - * update.c (special_file_mismatch): Get hardlinks from - vp->hardlinks instead of from vp->other_delta. - * rcs.c (free_rcsvers_contents): Comment about freeing hardlinks - member. - (RCS_checkout) [PRESERVE_PERMISSIONS_SUPPORT]: Get hardlinks from - vers->hardlinks list instead of vers->other_delta. - - ... and removed obsolete code from earlier revs. - * hardlink.c, hardlink.h (list_files_linked_to, - cache_hardlinks_proc, list_files_proc, set_hardlink_field_proc): - Removed. - * hardlink.h: Removed `links' member from hardlink_info struct. - * commit.c (commit): Remove the call to cache_hardlinks_proc. - (check_fileproc) [PRESERVE_PERMISSIONS_SUPPORT]: Removed reference - to hlinfo->links. - * hardlink.c (update_hardlink_info): Same. - * update.c (get_linkinfo_proc): Same. - - * rcs.c (RCS_checkout) [PRESERVE_PERMISSIONS_SUPPORT]: Use - vp->hardlinks and find_checkedout_proc to find recently-updated - files that may be hardlinked. - * update.c (special_file_mismatch): Use List * structures and - compare_linkage_lists for rev1_hardlinks and rev2_hardlinks. - -1998-03-16 Larry Jones <larry.jones@sdrc.com> - - * server.c (check_password): If shadow passwords are supported but no - entry is found in the shadow file, check the regular password file. - -1998-03-07 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Rename permissions test to perms since that is what - each of its individual tests are named. - * sanity.sh (perms symlinks hardlinks): Change CVSROOT to - CVSROOT_DIRNAME where appropriate. - (perms symlinks hardlinks): Disable/adjust the meat of the tests for - remote. - (symlinks): Link to ${TESTDIR}/fumble rather than - /fumble/mumble/grumble. We shouldn't be making assumptions about - what might exist in random directories outside ${TESTDIR}. - * hardlink.c (cache_hardlinks_proc): Add comment about trimming - whitespace. - -1998-03-07 Tim Pierce <twp@skepsis.com> - - * rcs.c (RCS_checkout): Negation bug when checking out symlinks: - existence_error should be !existence_error. - * sanity.sh (permissions symlinks hardlinks): New tests, for - PreservePermissions. - -1998-03-04 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version number to 1.9.26.1. - - * Version 1.9.26. - - * entries.c, cvs.h (Entries_Open): New argument update_dir; use it - in error message. - * add.c, checkout.c, client.c, find_names.c, import.c, recurse.c, - update.c: Pass it (as NULL except in call_in_directory). - * entries.c (Subdirs_Known): Just return if there is no CVSADM - directory (as in subdir_record). - * sanity.sh (conflicts3): New tests conflicts3-20a and - conflicts3-23 test for these fixes. - - * commit.c (commit): Only set up hardlist if preserve_perms. - - * commit.c, import.c, no_diff.c, parseinfo.c, rcs.c, rcscmds.c, - update.c: Omit the preserve_perms code if - PRESERVE_PERMISSIONS_SUPPORT is not defined. Much of that code - won't even compile on non-unix systems. - - * hardlink.c, hardlink.h: Use the 'standard' copyright (as found - in server.c). - * commit.c, rcs.c: Minor whitespace changes to Tim's submission. - * commit.c (check_fileproc), update.c (get_linkinfo_proc): Remove - unused variable delta. - * hardlink.c (set_hardlink_field_proc), update.c - (get_linkinfo_proc): Return a value rather than falling off the - end of the function. - -1998-03-02 Tim Pierce <twp@skepsis.com> - - * update.c (special_file_mismatch): Compare the hard links of the - two revisions. - - * rcs.c (RCS_checkout): - - * hardlink.c, hardlink.h: New files. - (hardlink_info): New struct. - (hardlist, working_dir): New variables. - (list_files_proc, cache_hardlinks_proc, set_hardlink_field_proc, - lookup_file_by_inode, update_hardlink_info, list_files_linked_to): - New functions. - - * Makefile.in (SOURCES): Add hardlink.c. - (OBJECTS): Add hardlink.o. - (HEADERS): Add hardlink.h. - * commit.c: Include hardlink.h. - (commit): Save the working directory before recursing. Walk the - hardlink list, calling set_hardlink_field_proc on each node. - (check_fileproc): Add each file's link information to hardlist. - * rcs.c: Include hardlink.h. - (RCS_checkin): Save list of hardlinks in delta node. - (RCS_checkout): Look up the file's `hardlinks' delta field, and - see if any of the files linked to it have been checked out - already. Link to one of those files if so. - * update.c: Include hardlink.h. - (get_linkinfo_proc): New function. - (do_update): Extra recursion to collect hardlink info. - (special_file_mismatch): Reparse the RCS file if necessary. - - fsortcmp is now used by several files, so let's make it extern. - * hash.c, hash.h (fsortcmp): New function. - * find_names.c (fsortcmp): Removed. - * lock.c (fsortcmp): Removed. - -1998-03-03 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (conflicts3): New tests conflicts3-14a, - conflicts3-14b, and conflicts3-21, conflicts3-22 test that we can - skip over a working directory with a CVSADM directory missing. - -1998-02-26 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (conflicts3): Tests conflicts3-16 and conflicts3-20 - test that we include update_dir in messages. Rename test - conflicts3-14 to fix typo. - -Sun Feb 22 23:14:25 1998 Steve Cameron <steve.cameron@compaq.com> - and Ian Lance Taylor <ian@cygnus.com> - - * update.c (tag_update_dir): New static variable. - (update_dirent_proc): If no tag or date were specified when - creating a subdirectory, use the tag and/or date of the parent - directory. - (update_dirleave_proc): If we set the tag and/or date in - update_dirent_proc, reset them when we leave the directory. - * sanity.sh (branches2): New set of tests for above patch, and - related behaviour. - -Sun Feb 22 13:31:51 1998 Ian Lance Taylor <ian@cygnus.com> - - * commit.c (lock_RCS): Don't call RCS_rewrite. - - * update.c (patch_file): If the revision is dead, let - checkout_file handle it. - * sanity.sh (death2): Add test for above patch: add - death2-10a, death2-10b, death2-13a, and adjust - death2-{2,4,5,11,14,diff-11,diff-12,19}. - - * cvs.h (RCS_FLAGS_KEEPFILE): Define. - * rcs.c (RCS_checkin): If RCS_FLAGS_KEEPFILE is set in the flags - parameter, don't unlink the working file. - * checkin.c (Checkin): Don't copy the file. Instead pass - RCS_FLAGS_KEEPFILE to RCS_checkin, and only check the file out - again if it has changed. - -1998-02-21 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (rcs_internal_unlockfile, RCS_rewrite): Don't assume errno - means anything just because ferror is set. - -Sat Feb 21 20:02:24 1998 Ian Lance Taylor <ian@cygnus.com> - - * Makefile.in (clean): Change "/bin/rm" to "rm". - - * buffer.c (buf_append_buffer): Correct typo in comment. - * rcs.c (RCS_putadmin): Likewise. - -Fri Feb 20 17:53:06 1998 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (rcs_internal_unlockfile): Pass errno when calling error - because ferror is true. - -1998-02-20 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (abspath): Don't assume that we can't write to /; this - is the kind of thing that is sure to break sooner or later - (especially on Windows). - - * sanity.sh: Add summary of which modules tests are which (at - "modules"). Move cvsadm, abspath, and toplevel next to modules. - Add comments to clarify the structure (such as it is). - -Fri Feb 20 12:47:14 1998 Larry Jones <larry.jones@sdrc.com> - - * admin.c (admin_fileproc): Better fix for -b. - - * rcs.c (RCS_whatbranch): Back out previous change. - (RCS_getversion): Ditto. - (RCS_setbranch): Treat an empty revision string like a null pointer. - -1998-02-18 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_whatbranch): Fix indentation. - - * patch.c (patch_fileproc): Check for errors from fclose; check - for errors from fopen properly. - -Wed Feb 18 16:03:37 1998 Larry Jones <larry.jones@sdrc.com> - - * admin.c (admin_fileproc): Convert -b argument from symbolic name - to revision number before storing in the RCS file. - * rcs.c (RCS_whatbranch): Allow numeric as well as symbolic revision. - (RCS_getversion): Take advantage of above. - * sanity.sh (admin): Add/revise/renumber admin-10c, admin-11a, - admin-12, and admin-12a to check above. - - * commmit.c (lock_RCS): Minor clean-up. - - * sanity.sh (abspath-6a): Don't depend on the sepcific contents of - CVSROOT, it depends on which other tests have been run. - -Wed Feb 18 01:56:04 1998 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (putsymbol_proc): Use putc and fputs rather than fprintf. - (RCS_putadmin): Don't call RCS_symbols if the symbols have not yet - been converted to a list. - - * rcs.c (rcsbuf_cache, rcsbuf_cache_open, rcsbuf_cache_close): New - static functions to avoid closing and reopening the RCS file. - (cached_rcs, cached_rcsbuf): New static variables. - (RCS_parse): Call rcsbuf_cache_close. Don't call fclose. - (RCS_parsercsfile): Likewise. - (RCS_parsercsfile_i): Call rcsbuf_cache rather than - rcsbuf_close. Call fclose on error. Remove comment about - inefficiency of opening file twice. - (RCS_reparsercsfile): Call rcsbuf_cache_open rather than fopen and - rcsbuf_open. Call rcsbuf_cache rather than rcsbuf_close and - fclose. - (RCS_fully_parse, RCS_checkout, RCS_deltas): Likewise. - (RCS_rewrite): Likewise. - (RCS_checkin): Call rcsbuf_cache_close. - - * rcs.c (RCS_copydeltas): Fix code which checks for an extra - newline in buffered data. - - * rcs.c (rcsbuf_getkey): Save an indirection by using start rather - than *valp when trimming trailing whitespace from value. - - * rcs.c (rcsbuf_get_buffered): New static function. - (RCS_copydeltas): After we have done all the required special - actions, and inserted any new revision, just copy the file bytes - directly, rather than interpreting all the data. - (count_delta_actions): New static function. - * sanity.sh (rcs): Add rcs-6a and rcs-6b to commit a new branch - revision, to force CVS to interpret all the data, rather than just - copying it. Adjust rcs-5 to add a branch tag. Adjust rcs-8a and - rcs-14 for the changes created by rcs-6b. - -Tue Feb 17 18:34:01 1998 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh (cvsadm, diffmerge2): Remove directories at the end of - the test. - - * import.c (expand_at_signs): Rewrite to use memchr and fwrite - rather than putc. - - Rewrite RCS file reading routines for speed: - * rcs.c (struct rcsbuffer): Define. - (rcsbuf_open, rcsbuf_close, rcsbuf_getkey, rcsbuf_getrevnum, - rcsbuf_fill, rcsbuf_valcopy, rcsbuf_valpolish, - rcsbuf_valpolish_internal, rcsbuf_ftell): New static functions. - (getrcskey, getrcsrev, getrevnum): Remove. - (many functions): Change to use new rcsbuf functions instead of - old getrcskey/getrcsrev/getrevnum functions. - (RCS_reparsercsfile): Add rcsbufp parameter. Change all callers. - (RCS_deltas): Add rcsbuf parameter. Change all callers. - (getdelta): Change fp parameter to rcsbuf parameter. Change all - callers. - (RCS_getdeltatext): Add rcsbuf parameter. Change all callers. - (RCS_copydeltas): Add rcsbufin parameter. Change all callers. - * rcs.h (RCS_reparsercsfile): Update declaration. - * admin.c (admin_fileproc): Update calls to RCS_reparsercsfile for - new parameters. - -1998-02-17 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (toplevel): Also clean up second-dir (not a new - bug, but triggered by running tests as "toplevel abspath"). - - * create_adm.c (Create_Admin): Just print update_dir to tell the - user where we are; not the whole xgetwd. Cleaner than - Noel's change (which also had problems in errno handling). - * sanity.sh (toplevel-12): Update accordingly. - -Tue Feb 17 02:32:21 1998 Noel Cragg <noel@swish.red-bean.com> - - [These mods make "checkout" work with "-d /absolute/pathname" - once again.] - - * checkout.c (checkout_proc): the -d flag on the command line - should override the -d flag in the modules file if the latter is - an absolute path. The loop that assembles the list of directories - to build has been reorganized slightly to prepare for rewriting - with last_component rather than assuming '/' as a path separator. - Also added to that loop was some code to handle absolute - pathnames. - (build_dirs_and_chdir): add a new argument that tells this routine - whether or not to check before it creates and populates - directories or not. - - * filesubr.c (last_component): return the top-level directory when - asked about the top-level directory. - - * sanity.sh (toplevel-12): change test to reflect the new style of - this error message. - - * create_adm.c (Create_Admin): include the directory in the error - message. - -1998-02-16 Jim Kingdon <kingdon@harvey.cyclic.com> - - * diff.c (diff_fileproc), import.c (import, add_rcs_file), rcs.c - (RCS_cmp_file): Don't ignore errors from CVS_UNLINK and fclose. - - * patch.c (patch_fileproc): Check for errors from fclose; if we - get -1 from getline check for end of file vs. error. - - * rcs.c (RCS_checkout): Comment return value (0/1, not -1). - * commit.c, diff.c, mkmodules.c, patch.c, rcs.c, update.c: Update - to match this convention. Don't suppress errors based on - quiet or really_quiet variables. - - Fix a longstanding bug which also makes stamps-8kw in make - remotecheck work again (it stopped working with Ian's 8 Feb 98 - checkin): - * client.c, client.h (change_mode): If new argument respect_umask - is set, then honor the umask. - * client.c, server.c: Update callers. - - Cleanups to Tim's checkin: - * rcs.c (RCS_checkout): Use existence_error not ENOENT. - * commit.c (checkaddfile): Remove comment about whether we want to - check for errors from fclose; there is no reason not to. - * rcs.c (RCS_checkout), update.c (special_file_mismatch): sscanf - on %ld requires an unsigned long, not a dev_t. - * update.c (special_file_mismatch): Remove unused variable - check_devnums. - * mkmodules.c (config_contents): Between two settings, use a blank - line not a "#" line. - -1998-02-15 Tim Pierce <twp@skepsis.com> - - [This is the code as submitted. I'll be checking in my cleanups - shortly. This work sponsored by Abbott Labs. -kingdon] - - Support for device special files, symbolic links, user and group - ownerships, and file permissions. - - * parseinfo.c: (parse_config): Handle new config variable - `PreservePermissions'. - * mkmodules.c (config_contents): Add new PreservePermissions var. - - * rcs.c, rcs.h (preserve_perms): New variable. - (RCS_checkout, RCS_checkin): Support for newphrases `owner', - `group', `permissions', `special', `symlink'. - (RCS_checkout): If `workfile' and `sout' are symlinks, remove them - before attempting to open them for writing. - * import.c (add_rcs_file): Support for newphrases. Do not attempt - to read data from special files or symlinks. Error message - `cannot fstat' is now `cannot lstat'. - - New metrics for deciding when two files are different: - - * update.c, cvs.h (special_file_mismatch): New function. - (merge_file, join_file): Call it. - * no_diff.c (No_Difference): Call it. - - * filesubr.c (xcmp): Consider files to be different if they are of - different types; if they are symlinks which link to different - pathnames; or if they are devices with different device numbers. - Error message is now `cannot lstat'. - * rcs.c (RCS_cmp_file): Use `xcmp' to compare files, simplifying - the special handling for nonregular files. - - * rcscmds.c (diff_exec, diff_execv): If asked to obtain diffs for - special files, report no differences. - - Miscellaneous changes to make special file support possible: - - * commit.c (fix_rcs_modes): Don't attempt to `fix' permissions on - a symlink. - - * import.c (add_rcs_file): Don't try to close fpuser if it was - never opened (e.g. when operating on a symlink). - - * filesubr.c, cvs.h (isdevice, xreadlink): New functions. - * filesubr.c (copy_file): Handle special files and symlinks. - (xchmod): Do nothing if `preserve_perms' is set. - - * commit.c (checkaddfile): Replace `copy_file (DEVNULL, ...)' with - fopen/fclose calls. Copy_file no longer attempts to read data - from device files. - - * filesubr.c (islink): Use CVS_LSTAT, not lstat. - * vers_ts.c (time_stamp, time_stamp_server): Use CVS_LSTAT, not stat, - to get symlinks right. - * subr.c (get_file): Same. Don't attempt to read from special - files or symlinks. - - * classify.c (Classify_File): Doc fix. - -Fri Feb 13 17:07:32 1998 Eric Mumpower <nocturne@cygnus.com> - and Ian Lance Taylor <ian@cygnus.com> - - Fix some file system ordering problems found on Irix 6.4: - * sanity.sh (basic2): Use dotest_sort for test 56. - (importb): Use dotest_sort for tests importb-1 and importb-2. - (head): Use dotest_sort for test head-1. - -Thu Feb 12 15:15:33 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * import.c (add_rcs_file): If add_logfp is NULL, don't call fperror. - -11 Feb 1998 Andy Piper - - * server.c (cvs_output_binary): Use OPEN_BINARY not _O_BINARY. - -Mon Feb 9 18:34:39 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - Tweaks to Ian's checkin: - * update.c (merge_file): Remove comment about sending file to - client before the message. It doesn't apply to this code any more - (it does apply to checkout_file, but I'm not sure it is important - to have such a comment anyway). - * buffer.c (buf_default_memory_error, buf_length): Reindent. - * server.h: Declare struct buffer before use. - -Mon Feb 9 21:05:28 1998 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_fully_parse): Call getrevnum rather than getrcsrev. - Don't bother with ungetc. - - * rcs.c (getrcsrev): Rewrite to simply call getrevnum. - -Sun Feb 8 15:49:39 1998 Ian Lance Taylor <ian@cygnus.com> - - Don't have the server check out a revision into a file and then - immediately read the file; just read into a buffer instead. - * update.c: Include buffer.h. - (update_fileproc): Let checkout_file call server_updated. - (checkout_file): Add merging and update_server parameters. Change - all callers. If server_active, don't mess with backup files. If - server_active, copy the revision into a buffer rather than a file - when possible. If update_server, call server_updated. Fix - handling of error status. - (checkout_to_buffer): New static function used by checkout_file. - (merge_file): Let checkout_file call server_updated. - (join_file): Likewise. - * server.c (server_updated): Change file_info parameter to mode - parameter. Add filebuf parameter. Change all callers. If - filebuf is not NULL, don't read the file. - * server.h (server_updated): Update declaration. - * buffer.c (buf_free): New function. - (buf_append_buffer): New function. - (buf_length): New function. - * buffer.h (buf_free, buf_append_buffer, buf_length): Declare. - - * buffer.c: (buf_initialize): If the memory parameter is NULL, use - buf_default_memory_error. - (buf_default_memory_error): New static function. - * buffer.h (BUFMEMERRPROC): Define typedef. - * client.c (buf_memory_error): Remove. - (start_server): Pass NULL rather than buf_memory_error as buffer - memory error function. - -Sat Feb 7 16:27:30 1998 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_parsercsfile_i): Read the expand keyword from the RCS - file. We do this because Version_TS calls RCS_getexpand in many - common cases, and we don't want to reopen the file just for that. - (RCS_reparsercsfile): Skip the expand keyword. - (RCS_getexpand): Don't call RCS_reparsercsfile. - - * rcs.c (STREQ): New macro. In all string equality tests in the - file, replace strcmp with STREQ. - -Fri Feb 6 16:14:49 1998 Ian Lance Taylor <ian@cygnus.com> - - * update.c (checkout_file): If we've already removed the backup - file once, don't try to remove it again. - - * filesubr.c (unlink_file_dir): Call stat rather than isdir, and - don't call unlink if the file does not exist. - - * myndbm.c (mydbm_load_file): Rename line_len to line_size. Call - getstr rather than getline, to avoid any confusion between \n and - \012. Use the line length returned by getstr rather than calling - strlen. Remove local variable len. - -Fri Feb 6 13:23:46 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_parsercsfile_i): Don't suppress errors on - really_quiet. - (RCS_parsercsfile_i, RCS_reparsercsfile, RCS_fully_parse, - RCS_deltas, getdelta, getrcskey, RCS_getdeltatext): - Check for errors. Include errno in error messages. Include - filename in error messages. Pass new argument to getrcskey. - (getrcskey): New argument NAME, so we can report errors ourself. - -Fri Feb 6 12:10:18 1998 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_reparsercsfile): Don't use ftell/fseek; just keep - track of whether we've already read a key/value pair. Use sizeof - rather than strlen for a constant string. Pass the current key - and value to getdelta, and get them back as well. - (getdelta): Add keyp and valp parameters. Don't use ftell/fseek; - just return the key/value pair to the caller. Don't allocate - vnode before we know we need it. Check one getrcskey return - value. Use sizeof rather than strlen for a constant string. - - * rcs.c (getrcskey): Correct comment describing return value. - -Thu Feb 5 22:51:13 1998 Ian Lance Taylor <ian@cygnus.com> - - * subr.c (getcaller): Cache the result, so that we don't keep - searching the password file. - -Wed Feb 4 23:31:08 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (max_rev): Don't prototype. Interesting that noone - complained about this until now. - -4 Feb 1998 Jim Kingdon - - * rcs.c (RCS_checkin): When adding a new file, read it - with "rb" if binary. - -Fri Jan 30 11:32:41 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Also test "first-dir" as the regexp in loginfo in - addition to ALL. - - * main.c (main): Update year in copyright notice to 1998. - -Thu Jan 29 00:01:05 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version number to 1.9.25. - - * Version 1.9.24. - - * sanity.sh (multibranch2): File file2 and tests multibranch2-13 - through multibranch2-15 test a slightly different case than the - rest of multibranch2. - - * mkmodules.c (cvswrappers_contents): Rewrite. The text didn't - describe -k and had various other problems. - -28 Jan 1998 Karl Fogel and Jim Kingdon - - New feature to let server tell client about wrappers. - * client.h (struct response): Add comment about args being - '\0' terminated when passed to handle_* functions. - * client.c (start_server): send "wrapper-sendme-rcsOptions" to - server iff supported. - (responses): new response "Wrapper-rcsOption"; allows the server - to send certain lines from its cvswrappers file. - (handle_wrapper_rcs_option): new func, handles "Wrapper-rcsOption" - response from server. - * server.c (serve_wrapper_sendme_rcs_options): new func, sends - server side CVSROOT/cvswrappers rcs option lines to client. - (requests): new request "wrapper-sendme-rcsOptions"; if received, - we know we can send "Wrapper-rcsOption..." to the client. - * wrapper.c (wrap_unparse_rcs_options): new func; repeated calls - step down the wrapper list returning rcs option entries, but - repackaged as cvswrappers lines. - (wrap_setup): new guard variable `wrap_setup_already_done'; if - this function has run already, just return having done nothing. - Add comment concerning environment variable. - * cvs.h: declare wrap_unparse_rcs_options(). - -Tue Jan 27 18:27:19 1998 Ian Lance Taylor <ian@cygnus.com> - - * rtag.c (rtag_dirproc): Call ignore_directory, and skip the - directory if it returns true. - * sanity.sh (modules4): New set of tests to test some aspects of - excluding directories in the modules file, including the above - patch. - -Thu Jan 22 10:05:55 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (serve_kopt): Check for length of arg. Based on - inspection of the code, plugs a buffer overrun security hole which - was introduced Monday. - - * server.c (serve_is_modified): Don't call xmalloc; we aren't - allowed to call error() here. Remove duplicate (and potentially - confusing) variable 'p'. - - * log.c (log_fileproc): Look for first character of version - '0' AND second character '\0', rather than OR. I didn't try to - come up with a test case but this looks like a simple thinko - (albeit one which would show up in obscure cases if at all). - -Tue Jan 20 19:37:53 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (send_dirent_proc): Don't send nonexistent directories - unless noexec. - * sanity.sh (modules2): New tests modules2-13 through modules2-18 - test for this fix. - -Mon Jan 19 11:17:51 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (serve_kopt): New function. - (requests): Add "Kopt" request. - (kopt): New variable. - (serve_is_modified): Write kopts from there into entries. - (serve_modified): Call serve_is_modified so we do the same. - Declare serve_modified and serve_is_modified. - * vers_ts.c (Version_TS): Set ->options even for a dummy ("D" - timestamp) entry. - * import.c (process_import_file): Check for -k options. - * client.c (client_process_import_file): Send Kopt request. - (send_fileproc): Likewise, for "cvs add". - * sanity.sh: Enable test binwrap3-sub2-add1 for remote. - Add -I .cvswrappers to binwrap3-2a; adjust binwrap3-2d - accordingly. Tests for this fix. - -Mon Jan 19 08:48:59 1998 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (errmsg1): Append test 168 output to log file. - -Sat Jan 17 08:01:51 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (ann-10, ann-11): Don't make assumptions about the - number of characters in the username. - -Fri Jan 16 15:34:02 1998 Larry Jones <larry.jones@sdrc.com> - - * diff.c (diff_fileproc): Free label1 and label2 when finished. - - * edit.c (editor_set): Don't free edlist until after we're - done using it. - - * rcscmds.c (RCS_merge): Free xrev1 and xrev2 when finished. - - * subr.c (make_message_rcslegal): Don't access uninitialized or - unallocated memory; only strip trailing blank lines. - * sanity.sh (log-3): Enhance to test this fix. - -Fri Jan 16 12:41:03 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Add keywordlog to list of tests run by default. - - * rcs.c (RCS_deltas): Don't call cvs_output if length is zero; - passing zero length to cvs_output does not mean output zero - bytes. The 27 Dec 1997 change to no longer '\0'-terminate the - ->text field turned this from a time bomb to a user-visible bug. - * sanity.sh (ann): New tests, test for this fix and other annotate - behaviors. - -Thu Jan 15 23:52:00 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * root.c (root_allow_ok): If inetd.conf didn't specify an - --allow-root options at all, we know we are in trouble. Give a - specific error message. - -Thu Jan 15 21:24:59 1998 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh (dotest_sort): New variant of dotest which sorts the - output, for use when the output depends upon details of the file - system, typically when doing an import. - (rdiff): Use dotest_sort for rdiff-1. - (ignore): Use dotest_sort for 188a, 188b, 189d, 190, and 191. - - * sanity.sh: (TESTSHELL): New variable. - (editor, info, reserved): Use TESTSHELL in temporary script. - - * sanity.sh (ignore): Do all tests in subdirectory, to avoid - conflict between cvsroot and CVSROOT on Windows. - (binwrap3, mwrap, info, config): Likewise. - - * sanity.sh (binfiles2): Correct test name binfile2-7-brmod to - binfiles2-7-brmod. - - * release.c (release_delete): If __CYGWIN32__ is defined, don't - worry about mismatched inodes. This is a hack, but then I think - the test is rather peculiar anyhow. - -Thu Jan 15 16:07:36 1998 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh (reserved-9): Use ${PROG} instead of "cvs". - -Wed Jan 14 15:43:13 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Split ChangeLog into ChangeLog-97 and ChangeLog. - * Makefile.in (DISTFILES): Add ChangeLog-97. - -13 Jan 1998 Jim Kingdon - - * client.c: Declare handle_mt. - -Tue Jan 13 22:21:30 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Add comment about how pwd and /bin/pwd often differ - in behavior (but are not guaranteed to). - -Tue Jan 13 13:49:53 1998 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh: When setting TMPPWD use just pwd, not /bin/pwd. - - * update.c (checkout_file): Don't pass set_time as true to - Version_TS if the file is dead. - * sanity.sh (modules): Add tests modules-155c6 through - modules-155c8 to test for above patch (without the above patch, - modules-155c8 will fail when remote). - -Tue Jan 13 10:37:02 1998 Larry Jones <larry.jones@sdrc.com> - - * client.c (send_modified): Change bufsize and newsize from int - to size_t to avoid type clashes in call to read_and_gzip. - -Tue Jan 13 10:33:02 1998 Larry Jones <larry.jones@sdrc.com> - - * zlib.c (read_and_gzip): Set finish to 0; it was uninitialized. - -Tue Jan 13 10:26:43 1998 Larry Jones <larry.jones@sdrc.com> - - * add.c, rcs.c: Plug memory leaks. - -Mon Jan 12 10:45:27 1998 Larry Jones <larry.jones@sdrc.com> - - * server.c (mkdir_p): Don't try to create nameless directories - (i.e., given "/foo//bar", don't try to create "/foo/", - just "/foo" and "/foo//bar") since it isn't necessary and - it fails on some systems in unexpected ways. - -1998-01-11 enami tsugutomo <enami@but-b.or.jp> - - * rcs.c (linevector_copy): Delete lines before overwriting them. - -Sat Jan 10 11:05:40 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvsrc.c, entries.c, login.c, logmsg.c, myndbm.c, patch.c, - release.c, server.c: Check for errors from getline, CVS_FOPEN, - fprintf, CVS_UNLINK and fclose. Note that the new errors are - nonfatal. This is because of conservatism more than because - it is always the best thing. - * login.c (get_cvs_password): Close the file when done with it. - * client.c (notified_a_file): If -1 return from getline, check - feof rather than assuming errno is set. - -Fri Jan 9 14:38:54 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (expand_proc): Also output server_dir in - "Module-expansion", not just in output_dir ("Created", &c). - * sanity.sh (modules2): New tests modules2-9 through modules2-12 - test for this. - -Thu Jan 8 12:56:55 1998 Yasutoshi Hiroe <hiroe@rgk.ricoh.co.jp> - - * import.c (import): Don't strcat on uninitialized memory. Fixes - possible SIGSEGV with zero-length message. - -Tue Jan 6 22:56:29 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (crerepos): Fix mistaken variable name which caused us - not to clean up at the end of the test. - -Mon Dec 22 01:40:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add): Also look for .cvswrappers files. - * sanity.sh (binwrap3): New tests binwrap3-2*, binwrap3-sub2-add* - test for this. - -Tue Jan 6 11:50:38 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (crerepos): New tests crerepos-8 through crerepos-18 - test behaviors when mixing repositories. - -Sun Jan 4 17:40:22 1998 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version number to 1.9.23. - - * Version 1.9.22. - - -For older changes see ChangeLog-97. diff --git a/contrib/cvs/src/ChangeLog-9194 b/contrib/cvs/src/ChangeLog-9194 deleted file mode 100644 index eb79efc..0000000 --- a/contrib/cvs/src/ChangeLog-9194 +++ /dev/null @@ -1,524 +0,0 @@ -Thu Sep 15 08:20:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * subr.c (run_setup, run_args): Check USE_PROTOTYPES if defined - instead of __STDC__, just like cvs.h does. - -Thu Sep 15 00:14:58 1994 david d `zoo' zuhn <zoo@monad.armadillo.com> - - * main.c: rename nocvsrc to use_cvsrc, don`t read ~/.cvsrc when -H - has been seen - -Wed Sep 14 21:55:17 1994 david d `zoo' zuhn <zoo@monad.armadillo.com> - - * cvs.h, subr.c: use size_t for xmalloc, xrealloc, and xstrdup - parameters - - * cvsrc.c: optimize away two calls of getenv - - * commit.c, subr.c: use mode_t for file mode values (Thanks to jtc@cygnus.com) - - * main.c: update copyrights in -v message - -Tue Sep 6 10:29:13 1994 J.T. Conklin (jtc@rtl.cygnus.com) - - * hash.c (hashp): Replace hash function with one from p436 of the - Dragon book (via libg++'s hash.cc) which has *much* better - behavior. - -Wed Aug 17 09:37:44 1994 J.T. Conklin (jtc@cygnus.com) - - * find_names.c (find_dirs): Use 4.4BSD filesystem feature (it - contains the file type in the dirent structure) to avoid - stat'ing each file. - -Tue Aug 16 11:15:12 1994 J.T. Conklin (jtc@cygnus.com) - - * rcs.h (struct rcsnode): add symbols_data field. - * rcs.c (RCS_parsercsfile_i): store value of rcs symbols in - symbols_data instead of parsing it. - (RCS_symbols): New function used for lazy symbols parsing. - Build a list out of symbols_data and store it in symbols if it - hasn't been done already, and return the list of symbols. - (RCS_gettag, RCS_magicrev, RCS_nodeisbranch, RCS_whatbranch): - Use RCS_symbols. - * status.c: (status_fileproc): Use RCS_symbols. - -Thu Jul 14 13:02:51 1994 david d `zoo' zuhn (zoo@monad.armadillo.com) - - * src/diff.c (diff_fileproc): add support for "cvs diff -N" which - allows for adding or removing files via patches. (from - K. Richard Pixley <rich@cygnus.com>) - -Wed Jul 13 10:52:56 1994 J.T. Conklin (jtc@phishhead.cygnus.com) - - * cvs.h: Add macro CVSRFLPAT, a string containing a shell wildcard - expression that matches read lock files. - * lock.c (readers_exist): Reorganized to use CVSRFLPAT and to not - compute the full pathname unless the file matches. - - * rcs.h: Add macro RCSPAT, a string containing a shell wildcard - expression that matches RCS files. - * find_names.c (find_rcs, find_dirs): Use RCSPAT. - -Fri Jul 8 07:02:08 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * entries.c (Register): Pass two arguments to write_ent_proc, in - accordance with its declaration. - -Thu Jun 30 09:08:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * logmsg.c (do_editor): Fix typo ("c)continue" -> "c)ontinue"). - -Thu Jun 23 18:28:12 1994 J.T. Conklin (jtc@phishhead.cygnus.com) - - * find_names.c (find_rcs, find_dirs): use fnmatch instead of - re_comp/re_exec for wildcard matching. - * lock.c (readers_exist): Likewise. - -Fri May 20 08:13:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * modules.c (do_module): If something is aliased to itself, print - an error message rather than recursing. - -Fri May 6 19:25:28 1994 david d zuhn (zoo@monad.armadillo.com) - - * cvsrc.c (read_cvsrc): use open_file for error checking - -Sat Feb 26 10:59:37 1994 david d zuhn (zoo@monad.armadillo.com) - - * import.c: use $TMPDIR if available, instead of relying on /tmp - -Mon Jan 24 19:10:03 1994 david d zuhn (zoo@monad.armadillo.com) - - * update.c (joining): compare join_rev1 with NULL instead of - casting pointer to an int - - * options.h: remove S_IWRITE, S_IWGRP, S_IWOTH macros - - * logmsg.c: #if 0 around gethostbyname prototype - - * hash.c (printnode), find_names.c (add_entries_proc), - entries.c (write_ent_proc): correct declaration for function - (added void *closure) - - * cvs.h: header include order reorganization: First include the - program config headers (config.h, options.h). Then include any - system headers (stdio.h, unistd.h). Last, get the program - headers and any cvs supplied library support - - * commit.c: use xstrdup instead of strdup - - * cvs.h: redefined USE(var) macro; comment after an #endif - - * all .c files: remove the semicolon from after the USE(var) - -Sat Dec 18 00:17:27 1993 david d zuhn (zoo@monad.armadillo.com) - - * cvs.h: include errno.h if available, otherwise declare errno if - it's not somehow else defined - - * commit.c (checkaddfile): remove unused file argument from - RCS_nodeisbranch call - - * rcs.c (RCS_nodeisbranch): remove file from arguments (was unused) - - * rcs.h (RCS_nodeisbranch): remove file from prototype - - * main.c: don't use rcsid when printing version number (the CVS - version number is independent of the repository that it comes - from) - - * hash.c (printlist, printnode): use %p to print pointers, not %x - (avoids gcc format warnings) - - * cvs.h: define USE if GCC 2, to avoid unused variable warning - - * all .c files: use USE(rcsid) - - * Makefile.in (VPATH): don't use $(srcdir), but @srcdir@ instead - (COMMON_OBJECTS): define, and use in several places - (OBJECTS): reorder alphabetically - - * hash.c (nodetypestring): handle default return value better - - * modules.c (do_module): remove extra argument to ign_dir_add - - * main.c (main): initialize cvs_update_env to 0 (zero) - - * modules.c (do_module): return error code when ignoring directory - (instead of a bare return). error code should be zero here - - * cvs.h: add prototypes for ignore_directory, ign_dir_add - - * ignore.c: add comments about ignore_directory - - * root.c (Name_Root): remove unused variables has_cvsadm and path - - * checkin.c (Checkin): only use -m<message> when message is non-NULL - - * cvsrc.c (read_cvsrc): make sure homeinit is never used while - uninitialized (could have happened if getenv("HOME") had failed) - - * cvs.h: include unistd.h if available - -Fri Dec 17 23:54:58 1993 david d zuhn (zoo@monad.armadillo.com) - - * all files: now use strchr, strrchr, and memset instead of index, - rindex, and bzero respectively - -Sat Dec 11 09:50:03 1993 david d zuhn (zoo@monad.armadillo.com) - - * version.c (version_string): bump to +104z - - * Makefile.in: set standard directory variables, CC, and other - variables needed to be able to do 'make all' in this directory - - * import.c: implement -k<subst> options, for setting the RCS - keyword expansion mode - - * all files: use PROTO() macro for ANSI function prototypes - instead of #ifdef __STDC__/#else/#endif around two sets of - declarations - -Thu Nov 18 19:02:51 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * add.c (add), import.c (import), commit.c (commit): change - xmalloc & strcpy to xstrdup. - - * commit.c (remove_file): correct another static buffer problem. - -Wed Nov 10 15:01:34 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * recurse.c (start_recursion): directories in repository but not - in working directory should be added to dirlist. Fixes "update - -d dir" case. - - * version.c (version_string): bump to +103r. - - * commit.c (checkaddfile): mkdir attic only if it does not already - exist. comment changes. changed diagnostic about adding on a - branch. if a file is added on a branch, remove and replace the - internal representation of that rcs file. - -Tue Nov 9 18:02:01 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * add.c (add): if a file is being added on a branch, then say so; - add quotes around file names in error messages. - -Thu Nov 4 16:58:33 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * version.c (version_string): bump to +102r. - - * recurse.c (unroll_files_proc, addfile): new files, forward - decls, and prototypes. - (recursion_frame): new struct. - (start_recursion): rewrite to handle the case of "file1 file2 - dir1/file3". - - * rcs.c (RCS_parsercsfile): trap and error out on the case where - getrcskey tells us it hit an error while reading the file. - - * commit.c (lock_filesdoneproc): add comment about untrapped error - condition. - - * hash.c (addnode): comment change. - - * subr.c: add comment about caching. - - * sanity.sh: updated copyright. - -Wed Nov 3 14:49:15 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * version.c (version_string): bump to +101r. - - * hash.c (walklist): add a closure for called routines. All - callers, callees, and prototypes changed. - - * hash.c (nodetypestring, printnode, printlist): new functions for - dumping lists & nodes. - - * tag.c (tag_fileproc): fatal out on failure to set tag. - -Tue Nov 2 14:26:38 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * version.c (version_string): bump version to +99. - -Mon Nov 1 15:54:51 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - Change buffer allocation for check in messages from static to - dynamic. - * add.c (add): dynamically allocate message. - (build_entry): check (message != NULL) now that message is a - pointer. - * commit.c (got_message, commit, commit_fileproc, - commit_filesdoneproc, commit_direntproc): removed. Replaced by - (message != NULL). Dynamically allocate message. - * cvs.h: adjust do_editor prototype and forward decl. - (MAXMESGLEN): removed. - * import.c (import): dynamically allocate message. - * logmsg.c (do_editor): change return type to char *. Remove - message parameter. Slight optimization to algorythm for - removing CVSEDITPREFIX lines. Add comment about fgets lossage. - - * subr.c (xmalloc): change error message to print number of bytes - we were attempting to allocate. - -Fri Oct 29 14:22:02 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * add.c (add): prevent adding a directory if there exists a dead - file of the same name. - - * sanity.sh: update argument to diff from "+ignore-file" to - "--exclude=". - - * Makefile.in (TAGS): extend to work from an objdir. - -Mon Oct 18 18:45:45 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) - - * tag.c, rtag.c: change the default actions to make writing over - existing tags harder (but not impossible) - -Thu Oct 14 18:00:53 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) - - CVS/Root changes from Mark Baushke (mdb@cisco.com) - - * Makefile.in: added new file called root.c - - * create_adm.c: will create CVS/Root at the same time that the - other CVS files are being created - - * cvs.h: new CVSADM_ROOT define plus new function externs - - * main.c: default to using CVS/Root contents for CVSROOT - if neither the environment variable or the command line - "-d" switch is given. If either are given, perform a - sanity check that this directory belongs to that repository. - - * update.c: if CVS/Root does not exist, then create it - during an update -- this may be removed if CVS/Root becomes a - standard feature - - * root.c: implement new functions to manipulate CVS/Root - [this may be integrated with other utility functions in - a future revision if CVS/Root becomes a standard feature.] - -Wed Sep 29 17:01:40 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) - - * patch.c (patch_fileproc): output an Index: line for each file - -Mon Sep 6 18:40:22 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) - - * cvs.h: wrap definition of PATH_MAX in #ifndef PATH_MAX/#endif - -Tue Aug 9 21:52:10 1994 Mark Eichin (eichin@cygnus.com) - - * commit.c (remove_file): actually allocate space for the - filename, not just the directory. - -Tue Jul 6 19:05:37 1993 david d `zoo' zuhn (zoo@cygnus.com) - - * diff.c: patches to print an Index: line - -Mon Jun 14 12:19:35 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com) - - * Makefile.in: update install target - -Tue Jun 1 17:03:05 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) - - * Makefile.in: link cvs against libiberty - -Wed May 19 14:10:34 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) - - * ignore.c: add code for keeping lists of directories to ignore. - - * modules.c: new syntax for modules file, !dirname is added to - the list of directories to ignore - - * update.c: don't process directories on the ignore list - -Tue Apr 6 14:22:48 1993 Ian Lance Taylor (ian@cygnus.com) - - * cvs.h: Removed gethostname prototype, since it is unnecessary - and does not match prototype in <unistd.h> on HP/UX. - -Mon Mar 22 23:25:16 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) - - * Makefile.in: rename installtest to installcheck - -Mon Feb 1 12:53:34 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * Makefile.in (check, installtest): set RCSBIN so that we - explicitly test the appropriate version of rcs as well. - -Fri Jan 29 13:37:35 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * version.c: bump version to +2. - -Thu Jan 28 18:11:34 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * import.c (update_rcs_file): if a file was dead, be sure to check - in the new version. - - * update.c (checkout_file): if file_is_dead and we *did* have an - entry, scratch it. - -Tue Jan 26 16:16:48 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * sanity.sh: parcel into pieces for easier truncation when - debugging. - - * update.c (checkout_file): print the "no longer pertinent" - message only if there was a user file. - -Wed Jan 20 17:08:09 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * update.c (checkout_file): remove unused variable s. - (join_file): remove unused variables rev & baserev. Fix a typo. - - * commit.c (commit_fileproc): remove unused variable magicbranch. - - * sanity.sh: bring back test 45 even though it fails. Update - tests against imported files. - - * add.c (add_directory): move declaration of unused variable. - - * Makefile.in (xxx): when building in this directory, pass CC for - the recursion. - -Mon Jan 18 13:48:33 1993 K. Richard Pixley (rich@cygnus.com) - - * commit.c (remove_file): fix for files removed in trunk - immediately after import. - - * commit.c (remove_file): initialize some variables. Otherwise we - end up free'ing some rather inconvenient things. - -Wed Jan 13 15:55:36 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * Makefile.in (check, install, installtest): use the sanity test. - - * sanity.el: make into real functions and bind to sun keys. - - * sanity.sh: bring back to working order. Add test for death - after import. - -Tue Dec 22 17:45:19 1992 K. Richard Pixley (rich@cygnus.com) - - * commit.c (remove_file): when checking in a dead revision to a - branch as we are creating the branch, do not lock the underlying - revision. Also free some malloc'd memory. - -Wed Dec 2 13:09:48 1992 K. Richard Pixley (rich@cygnus.com) - - * RCS-patches: new file. - -Fri Nov 27 20:12:48 1992 K. Richard Pixley (rich@rtl.cygnus.com) - - Added support for adding previously removed files, as well as - adding and removing files in branches. - - * add.c (build_entry): add new argument, tag, so as to store in - Entries the per directory sticky tag under which a file is - added. Changed prototype and caller. - (build_entry): Do not prevent file additions if the file exists - in the Attic. - (add): if the file being adding was previously dead, say so, and - mark the Entries file with the addition. - * checkin.c (Checkin): adding with a tag no longer means to add, - then tag. Hence, remove the tagging operation. - * classify.c (Classify_File): if the base RCS version is dead, - then the file is being added. If a file being added already - exists in the attic, and the base RCS version is NOT dead, then - we have a conflict. - * commit.c (checkaddfile): add the list of srcfiles to calling - convention. Change prototype and callers. - (remove_file): add message and list of srcfiles to calling - convention. Change prototype and callers. When removing a file - with a tag, remove the tag only when the tag does not represent - a branch. Remove files by committing dead revisions in the - appropriate branch. When removing files from the trunk, also - move the RCS file into the Attic. - (check_fileproc): when adding, and looking for previously - existing RCS files, do not look in the Attic. - (commit_fileproc): adding files with tags now implies adding the - file on a branch with that tag. - (checkaddfile): When adding a file on a branch, in addition to - creating the rcs file in the Attic, also create a dead, initial - revision on the trunk and stub in a magic branch tag. - * cvs.h (joining, gca): added prototypes. - * rcs.c (RCS_getbranch): now global rather than static. - remove prototype and forward decl. - (parse_rcs_proc): use RCS_addnode. - (RCS_addnode): new function. - (RCS_parsercsfile): recognize the new RCS revision - newphrase, "dead". Mark the node for the revision. - (RCS_gettag): requesting the head of a file in the attic now - returns the head of the file in the attic rather than NULL. - (RCS_isbranch): use RCS_nodeisbranch. - (RCS_nodeisbranch): new function. - (RCS_isdead): new function. - * rcs.h (RCSDEAD): new macro for new rcs keyword. - (struct rcsversnode): new field to flag dead revisions. - (RCS_nodeisbranch, RCS_isdead, RCS_addnode): new functions, - new prototypes, new externs. - (RCS_getbranch): now global, so prototype and extern moved - to here. - * subr.c (gca): new function. - * update.c (join_file): add entries list to calling - convention. Caller changed. - (update): also search the Attic when joining. - (checkout_file): when joining, checkout dead revisions too. If - a file has died across an update then say so. - (join_file): support joins of dead files against live ones, live - files against dead ones, and added files. Change the semantic - of a join with only rev specified to mean join specified rev - against checked out files via the greatest common ancestor of - the specified rev and the base rev of the checked out files. - (joining): new function. - * vers_ts.c (Version_TS): ALWAYS get the rcs version number. - - * update.c (update): write the 'C' letter for conflicts. - - * cvs.h (ParseTag): remove duplicate extern. - - * add.c (add_directory): do not prompt for interactive - verification before adding a directory. Doing so prevents - scripted testing. - -Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) - - * Makefile.in, configure.in: removed traces of namesubdir, - -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced - copyrights to '92, changed some from Cygnus to FSF. - -Tue Dec 10 01:24:40 1991 K. Richard Pixley (rich at cygnus.com) - - * diff.c: do not pass an empty -r option to rcsdiff. - - * update.c: fix bug where return code from rcsmerge wasn't being - handled properly. - - * main.c: "rm" and "delete" now synonyms for "remove". - - * commit.c: abort if editor session fails, but remember to clear - locks. - - * Makefile.in: remove conf.h and checkin.configured on clean. - infodir belongs in datadir. - -Thu Dec 5 22:46:03 1991 K. Richard Pixley (rich at rtl.cygnus.com) - - * Makefile.in: idestdir and ddestdir go away. Added copyrights - and shift gpl to v2. Added ChangeLog if it didn't exist. docdir - and mandir now keyed off datadir by default. - -Wed Nov 27 02:47:13 1991 K. Richard Pixley (rich at sendai) - - * brought Makefile.in's up to standards.text. - - * fresh changelog. - - -For older changes, there might be some relevant stuff in the bottom of -the NEWS file, but I'm afraid probably a lot of them are lost in the -mists of time. diff --git a/contrib/cvs/src/ChangeLog-9395 b/contrib/cvs/src/ChangeLog-9395 deleted file mode 100644 index c2d2111..0000000 --- a/contrib/cvs/src/ChangeLog-9395 +++ /dev/null @@ -1,3731 +0,0 @@ -Note: this log overlaps in time with ChangeLog-9194. There was a time -during which changes which had been merged into the official CVS -(which produced releases such as 1.4A1 and 1.4A2) went into what has -become ChangeLog-9194, and changes which existed only at Cygnus went -into this file (ChangeLog-9395). Eventually the Cygnus release became -Cyclic CVS (as it was then called), which became CVS 1.5, so probably -all the changes in both (what are now) ChangeLog-9194 and -ChangeLog-9395 made it into 1.5. - -Sun Dec 31 17:33:47 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * import.c (add_rev): Revert portion of 31 Aug 95 change which - passes -u to ci instead of using a hard link. - * sanity.sh (import): Add test for above-fixed bug. - -Sun Dec 31 16:40:41 1995 Peter Chubb <peterc@bookworm.sw.oz.au> - and Jim Kingdon <kingdon@cyclic.com> - - * admin.c (admin_fileproc): Call freevers_ts before returning. - -Mon Dec 25 12:20:06 1995 Peter Wemm <peter@haywire.DIALix.COM> - - * logmsg.c (rcsinfo_proc): initialise line and - line_chars_allocated so they dont cause malloc problems within - getline(). This was causing rcsinfo templates to not work. - -Sun Dec 24 01:38:36 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * server.c (authenticate_connection): clarify protocol. - - * login.c (login): deprolixify the password prompt. - -Sat Dec 23 10:46:41 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * myndbm.h, myndbm.c (dbm_store): New function. - * myndbm.h (DBM): Add modified and filename fields. - * myndbm.c (dbm_open, dbm_close): Manipulate new fields. dbm_open - no longer fails if the file doesn't exist and O_CREAT is set. - * cvs.h (CVSROOTADM_VALTAGS): Added. - * tag.c, cvs.h (tag_check_valid): New function. - * update.c (update), checkout.c (checkout_proc), commit.c (commit), - diff.c (diff), patch.c (patch_proc), rtag.c (rtag_proc), tag.c (tag): - Call it. - * sanity.sh: Test for rejection of invalid tagname. - -Fri Dec 22 18:21:39 1995 Karl Fogel <kfogel@csxt.cs.oberlin.edu> - - * client.c (start_server): don't use kerberos if authenticating - server was specified. - -Fri Dec 22 16:35:57 1995 Karl Fogel <kfogel@csxt.cs.oberlin.edu> - - * login.c (login): deal with new scramble methods. - (get_cvs_password): same. - - * server.c (check_repository_password): remove arbitrary limit on - line length. - (authenticate_connection): use a separate variable for the - descrambled password, now that we no longer scramble in place. - Set `error_use_protocol' to 1 and just use error() where used to - do its job inline. - - * cvs.h (scramble, descramble): adjust prototype. - - * scramble.c (scramble, descramble): return char *. - -Fri Dec 22 13:00:00 1995 Jim Kingdon <kingdon@peary.cyclic.com> - - * release.c (release): If SERVER_SUPPORT is not defined, still - set up arg_start_idx. - - * release.c (release): When calling unedit, set argv[1] to - NULL (since argc is only 1). - - * edit.c: Pass dosrcs 0 to all calls to start_recursion. - None of the fileprocs were using it, so it just slowed things - down and caused potentially harmful checks for rcs files. - - * edit.c (send_notifications): In client case, do not readlock. - -Thu Dec 21 16:00:00 1995 Jim Kingdon <kingdon@peary.cyclic.com> - - Clean up Visual C++ lint: - * client.c (read_line): Change input_index and result_size to size_t. - (update_entries): Remove unused variables buf2, size_left, size_read. - (handle_mode): Prototype. - * client.c, client.h (send_to_server, read_from_server): Change - len to size_t. - * client.c (send_to_server): Change wrtn to size_t. - (read_from_server): Change red to size_t. - * client.c, myndbm.c, edit.c, fileattr.c: Include getline.h. - * checkin.c, commit.c, update.c: Include fileattr.h. - * commit.c, update.c: Include edit.h. - * edit.c (onoff_filesdoneproc): Prototype. - (ncheck_fileproc,edit_fileproc): Change "return" to "return 0". - (notify_do): Cast a signed value to unsigned before comparing - with unsigned value. - -Thu Dec 21 15:24:37 1995 Karl Fogel <kfogel@occs.cs.oberlin.edu> - - * client.c: don't include socket headers twice just because - both HAVE_KERBEROS and AUTH_CLIENT_SUPPORT are set. - (start_kerberos_server): if fail to connect to kerberos, print out - a more specific error message, mainly so pcl-cvs can know what - happened and not panic. - (start_server): don't assume sprintf() returns len - written (only some systems provide this); instead, have - send_to_server() calculate the length itself. - (send_modified): same. - (send_fileproc): same. - (send_file_names): same. - -Wed Dec 20 14:00:28 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (ignore_files): Move from here... - * ignore.c (ignore_files): ...to here. No longer static. Take - new argument PROC. - * cvs.h (ignore_files): Declare. - * client.c (send_filesdoneproc): Split off from - update_filesdone_proc. Pass new function send_ignproc to - ignore_files (to ask server about ignored file before printing - "?"). - * server.c: Rename outbuf from but_to_net and take it from - do_cvs_command to a global. Move initialization accordingly. - (serve_questionable): New function. - (requests): Add it. - * update.c (update_filesdone_proc): Remove client stuff. Pass new - function update_ignproc to ignore_files. - * cvs.h (joining, do_update): Move declarations from here... - * update.h: ...to here. - * cvs.h: Include update.h. - * update.c, client.c: Don't include update.h - * ignore.c, cvs.h: New variable ign_inhibit_server, set on -I !. - * import.c (import): Pass -I ! to server if specified. - (import_descend): If server, ignore CVS directories even if -I !. - * update.c (update), import.c (import): Only call ign_setup before - argument processing; don't call it again afterwards in client case. - * sanity.sh (ignore): Test above-fixed bugs and other ignore behaviors. - (dotest): New function. - Move modules checkin from modules test to start, so that other - tests can use mkmodules without a warning message. - -Wed Dec 20 13:06:17 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (send_to_server): don't check string's length twice. - -Wed Dec 20 02:05:19 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * login.c (login): took out debugging printf's. - (login): Removed unused variable `p'. - -Wed Dec 20 00:27:36 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * login.c (login): prefix scrambled password with 'A', so we know - which version of scrambling was used. This may be useful in the - future. - (get_cvs_password): skip past the leading 'A'. - Scramble $CVS_PASSWORD before returning it. - - * scramble.c: made this work. - -Tue Dec 19 17:45:11 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * login.c (cvs_password): new static var, init to NULL. - (login): scramble() the password before using it. - Verify the password with the server. - Check CVSroot more carefully to insure that it is - "fully-qualified". - (get_cvs_password): if cvs_password is not NULL, just return it. - Never prompt -- just tell user why failed, then exit. - Try CVS_PASSWORD environment variable first. - (construct_cvspass_filename): try CVS_PASSFILE environment - variable first. - - * client.h (connect_to_pserver): update prototype. - - * client.c (cvsroot_parsed): new static var. - (parse_cvsroot): set `cvsroot_parsed' to 1 when done. - (connect_to_pserver): return int. - Take `verify_only' arg. If it is non-zero, perform password - verification with the server and then shut down the connection and - return. - Call parse_cvsroot() before doing anything. - - * server.c (authenticate_connection): deal with verification - requests as well as authorization requests. - descramble() the password before hashing it. - - * cvs.h: prototype scramble() and descramble(). - - * Makefile.in: build scramble.o. - - * scramble.c: new file, provides trivial encoding but NOT real - encryption. - -Mon Dec 18 20:57:58 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * login.c (login): don't insert extra newlines. They were - harmless, but confusing. - -Mon Dec 18 15:32:32 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * hash.c, hash.h (findnode_fn): New function. - * hash.c (hashp): Tweak hash function so that findnode_fn works. - * update.c (ignore_files): Call findnode_fn, not findnode. - -Mon Dec 18 09:34:56 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * myndbm.c: Remove arbitrary limit. - - * client.c: Fix comment--Windows 95 requires NO_SOCKET_TO_FD, not - Windows NT. - -Mon Dec 18 01:06:20 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (server_sock): replaces `server_socket'. - (start_kerberos_server): added FIXME comment about how - NO_SOCKET_TO_FD is not dealt with in the kerberos case. - (connect_to_pserver): deal with NO_SOCKET_TO_FD case. - (read_line): deal with NO_SOCKET_TO_FD case. - (read_from_server): deal with NO_SOCKET_TO_FD case. - (send_to_server): deal with NO_SOCKET_TO_FD case. - (get_responses_and_close): deal with NO_SOCKET_TO_FD case. - - * client.c (send_to_server): error check logging. - (start_server): error check opening of logfiles. - (read_from_server): error check logging. - (read_line): use fwrite() to log, & error_check it. - Don't log if using socket style, because read_from_server() - already logged for us. - -Mon Dec 18 00:52:26 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (use_socket_style): new static var, init to 0. - (server_socket): new static var. - (connect_to_pserver): don't deal with logging here. - Caller changed. - (start_kerberos_server): don't deal with logging here either. - Caller changed. - -Mon Dec 18 00:40:46 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (send_modified): don't error-check `to_server'; - send_to_server() does that now. - -Mon Dec 18 00:19:16 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * login.c (get_cvs_password): Init `linebuf' to NULL. - free() `linebuf' and reset it for each new line. - (login): same as above. - - * client.c: Removed all the varargs prototyping gunk. - (to_server, from_server): make these static. - (from_server_logfile, to_server_logfile): new vars. - (start_server): init above two new vars to NULL. - (send_to_server): return void. - Correct bug in which amount to be written would be too high if the - loop ever ran more than once. - Log to `to_server_logfile' if it's non-NULL. - (read_from_server): new func, does raw reading from server. - Logs to `from_server_logfile' if it's non-NULL. - (update_entries): just use read_from_server() instead of looping - to fread() directly from `from_server'. - (read_line): Log to `from_server_logfile' if it's non-NULL. - - * client.h: send_to_server() returns void now. - (read_from_server): prototype. - -Sun Dec 17 19:38:03 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (checkout_proc), client.c, lock.c (readers_exist), - login.c, modules.c (cat_module, do_module): Remove arbitrary limits. - - * client.c (send_to_server): Fix typo (NULL -> '\0'). - (get_responses_and_close): Set server_started to 0 instead of - setting to_server and from_server to NULL. - * client.c: Make to_server and from_server static. - -Sun Dec 17 17:59:04 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.h (to_server, from_server): don't declare these anymore. - They are now entirely private to client.c (and in fact will go - away soon there too). - -Sun Dec 17 15:40:58 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.h: update prototype of send_to_server(). - - * client.c, watch.c, update.c, tag.c, status.c, rtag.c, remove.c, - release.c, patch.c, log.c, import.c, history.c, edit.c, diff.c, - commit.c, client.c, checkout.c, admin.c, add.c: - Convert all send_to_server() calls that used formatting to send - pre-formatted strings instead. And don't error check - send_to_server(), because it does its own error checking now. - - * client.c (send_to_server): don't use vasprintf(), just fwrite a - certain number of bytes to the server. And do error checking - here, so our callers don't have to. - (send_arg): use send_to_server() instead of putc()'ing - directly to `to_server'. - -Sun Dec 17 14:37:52 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * options.h.in (AUTH_CLIENT_SUPPORT, AUTH_SERVER_SUPPORT): - Define to 1 but leave commented out, instead of #undef'ing them. - This treats them like everything else in this file. - - * client.c: define server_started, init to 0. - (start_server): set server_started to 1. - - * client.h: declare `server_started', extern. - AUTH_CLIENT_SUPPORT moved here from cvs.h. - - * cvs.h: moved AUTH_CLIENT_SUPPORT stuff to client.h. - - * edit.c (notify_check): use new var server_started. - -Sun Dec 17 00:44:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (get_responses_and_close): Really stop ignoring ECHILD - errors. The Nov 30 1995 change claimed to do this, but the code - was not actually changed. - - * update.c (ignore_files): Revert H.J. Lu change; it was wrong for - directories and sometimes looked at sb.st_mode when it wasn't set. - * import.c (import_descend): Revert H.J. Lu change; it was wrong - for directories and the extra lstat call was an unnecessary - performance hit. - * sanity.sh (import): Add test for the second of these two bugs. - -Sat Dec 16 17:26:08 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (send_to_server): Remove arbitrary limit. Also remove - !HAVE_VPRINTF code; all relevant systems have vprintf these days. - -Sat Dec 16 21:35:31 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * checkout.c (checkout): use send_to_server() now. - -Sat Dec 16 21:18:16 1995 H.J. Lu (hjl@gnu.ai.mit.edu) - (applied by kfogel@cyclic.com) - - * import.c (import_descend): We ignore an entry if it is - 1. not a file, nor a link, nor a directory, or - 2. a file and on the ignore list. - - * update.c (ignore_files): We ignore any thing which is - 1. not a file, or - 2. it is a file on the ignore list. - -Sat Dec 16 00:14:19 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (send_to_server): corrected comment. - - * client.h: prototype new func send_to_server(). - - * add.c, admin.c, client.c, commit.c, diff.c, edit.c, history.c, - import.c, log.c, patch.c, release.c, remove.c, rtag.c, status.c, - tag.c, update.c, watch.c: - Use send_to_server() instead of writing directly to to_server. - - * client.c: conditionally include the right stuff for variable arg - lists. - (send_to_server): new func. - -Fri Dec 15 23:10:22 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * error.c: expanded comments. - - * client.c (connect_to_pserver): verbosify errors. - (connect_to_pserver): use send() and recv(), not write() and - read(). Sockets are not file descriptors on all systems. - -Fri Dec 15 22:36:05 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (connect_to_pserver): oops, removed old debugging - printf. - -Fri Dec 15 18:21:16 1995 Karl Fogel (kfogel@floss.cyclic.com) - - * client.c (auth_server_port_number): don't call htons(); - init_sockaddr() does that for us. - (init_sockaddr): zero the sockadder_in struct before doing - anything with it. IBM TCP/IP docs recommend this, and it can't - hurt. - -Fri Dec 15 15:21:53 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (connect_to_pserver): new var `port_number', initialize - with new func auth_server_port_number() and pass to - init_sockaddr(). - (auth_server_port_number): new func. Right now it just returns - `htons (CVS_AUTH_PORT)'. We'll probably add the ability to - specify the port at run time soon, anyway, so having this function - will make that easier. - -Wed Dec 6 18:08:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h: Add CVSREP. - * find_names.c (find_dirs): Skip CVSREP too. - * fileattr.h, fileattr.c: New files, to manipulate file attributes. - * hash.c (nodetypestring), hash.h (enum ntype): Add FILEATTR. - * hash.c, hash.h (list_isempty): New function. - * recurse.c (do_recursion): Call fileattr_startdir before - processing files in a directory and fileattr_write and - fileattr_free (after files, before recursing). - * watch.c, watch.h: New files, to handle notification features. - * edit.c, edit.h: New file, to handle new read-only checkout features. - * client.c, server.c: Add "Mode" request, to change the mode of a file - when it is checked in. - * main.c (cmds): Add "watch", "edit", "unedit", "watchers", "editors". - * main.c: Split command help from usg into new variable cmd_usage, - which. - (main): Add --help-commands option to print out cmd_usage. - * cvs.h: Declare watch, edit, unedit, watchers, editors. - * client.c, client.h: Add client_watch, client_edit, client_unedit, - client_watchers, client_editors. - * client.c, server.c: Add notification stuff. - * update.c (checkout_file, patch_file), checkin.c (Checkin): Check - _watched attribute when deciding read-only or read-write. - * commit.c (checkaddfile): Call fileattr_newfile to set attributes - on newly created files. - * release.c (release): - * cvs.h: Add CVSADM_NOTIFY and CVSADM_NOTIFYBAK. - * recurse.c (do_recursion): Call notify_check. - * commit.c (commit_fileproc): Call notify_do after committing file. - * client.c (get_responses_and_close): Set to_server and from_server - to NULL so that it is possible to tell whether we are speaking to - the server. - * cvs.h: Add CVSROOTADM_NOTIFY. - * mkmodules.c (main): Add CVSROOTADM_NOTIFY to filelist. - * Makefile.in (SOURCES,OBJECTS,HEADERS): Add new files mentioned above. - * lock.c, cvs.h (lock_tree_for_write, lock_tree_cleanup): New - functions, taken from old commit.c writelock code. As part of - this, fsortcmp and lock_filesdoneproc go from commit.c to lock.c. - So does locklist but it gets renamed to lock_tree_list. - * commit.c: Use lock_tree_*. - -Fri Dec 15 10:37:00 1995 J.T. Conklin <jtc@slave.cygnus.com> - - * tag.c (tag_usage): Added -r and -D flags to usage string. - (tag): Detect when user specifies both -r and -D arguments. - Pass -r and -D arguments to server. - -Thu Dec 14 11:56:13 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (start_rsh_server): use RSH_NEEDS_BINARY_FLAG to - conditionalize "-b" option to "rsh". - - * run.c (filter_stream_through_program): document return value and - error behavior. - - * client.c (filter_through_gunzip): pass the supposedly - superfluous "-d" option to gunzip, to avoid stimulating what seems - to be an argument-passing bug in spawn() under OS/2 with IBM - C/C++. Yucko. - -Wed Dec 13 20:08:37 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * options.h.in (RCSBIN_DFLT): Recommend specifying -b in - inetd.conf for pserver. That is a pretty good solution. - -Wed Dec 13 18:29:59 1995 Preston L. Bannister <pbannister@ca.mdis.com> - and Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (send_modified): make sure that vers and vers->options - are non-NULL before strcmp()'ing them with "-kb". - Initialize `bin' near where it is used, not at beginning of - function. - (update_entries): make sure `options' is non-NULL before - strcmp()'ing with "-kb". - Initialize `bin' near where it is used, not at beginning of - function. - -Tue Dec 12 18:56:38 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * options.h.in (RCSBIN_DFLT): document the probable need for this - to be set in the authenticating server. - -Tue Dec 12 11:56:43 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (expand_proc): If mfile is non-NULL, return it too as - part of the expansion. - * sanity.sh (modules): Add tests for above-fixed bug. - -Mon Dec 11 21:39:07 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * dog.c (flea_bath): Take `suds' arg. - All collars changed. - -Mon Dec 11 15:58:47 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * login.c (login): if client password file doesn't exist, create - it, duh. - - * main.c (main): die if CVSroot has access-method but no - username. - - * root.c: added some comments. - - * main.c: removed all code pertaining to the "-a" option. We - specify access-method in CVSroot now. - - * client.c (parse_cvsroot): new var, `access_method'. If CVSroot - is prepended with an access method (i.e., - ":pserver:user@host:/path"), then handle it. - - * login.c (login): use || when checking if CVSroot is "fully - qualified". - Prepend ":pserver:" before writing to ~/.cvspass. - (get_cvs_password): Take no parameters; we'll just use CVSroot to - get the password. - -Mon Dec 11 12:43:35 1995 adamg <adamg@microsoft.com> - - * error.c, client.c, remove.c, main.c: Add explicit casts for some - function pointers to remove warnings under MS VC. - * main.c (main): remove use of NEED_CALL_SOCKINIT in favor of the - more generic INITIALIZE_SOCKET_SUBSYSTEM. Note that the code assumes - that if INITIALIZE_SOCKET_SUBSYSTEM() returns, socket subsystem - initialization has been successful. - -Sat Dec 9 22:01:41 1995 Dan O'Connor <doconnor@tii.com> - - * commit.c (check_fileproc): pass RUN_REALLY flag to run_exec, - because it's okay to examine the file with noexec set. - -Sat Dec 9 20:28:01 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (update_entries): new var, `bin, init to 0. - Use it in determining whether to convert the file. - (send_modified): same as above. - -Fri Dec 8 17:47:39 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * server.c (downcase_string): removed. - (check_repository_password): don't deal with case-insensitivity - anymore. - - * options.h.in (CVS_PASSWORDS_CASE_SENSITIVE): deleted this. No - need for it anymore. - -Thu Dec 7 21:08:39 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * server.c (check_repository_password): when checking for false - prefix-matches, look for ':', not '@'. Duh. - -Thu Dec 7 18:44:51 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * options.h.in (CVS_PASSWORDS_CASE_SENSITIVE): replaces - CVS_PASSWORDS_CASE_INSENSITIVE; passwords are now insensitive by - default. Expanded explanatory comment. - - * login.c (get_cvs_password): Use memset(), not bzero(). I - botched this change earlier. - - * server.c (check_repository_password): no need to check - xmalloc()'s return value. - (check_repository_password): check for false prefix-matches (for - example, username is "theo" and linebuf contains user - "theocracy"). - -Thu Dec 7 14:49:16 1995 Jim Meyering (meyering@comco.com) - - * filesubr.c (isaccessible): Rename from isaccessable. - Update callers. - * cvs.h: Update prototype. - * main.c (main): Update callers. - * server.c (main): Update callers. - -Thu Dec 7 12:50:20 1995 Adam Glass <glass@NetBSD.ORG> - - * cvs.h: "isaccessible" is the correct spelling. - Also add "const" to second arg to make prototype match - declaration. - -Thu Dec 7 11:06:51 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c, login.c: memset() instead of bzero(). - -Thu Dec 7 00:08:53 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * server.c (authenticate_connection): document server's side of - the Authentication Protocol too. - - * client.c (connect_to_pserver): when printing out "unrecognized - response", also print out the offending response. - - * server.c (check_password): take `repository' arg too now. - Call check_repository_password() before checking /etc/passwd. - (check_repository_password): new func. - - * options.h.in (CVS_PASSWORDS_CASE_INSENSITIVE): new define, unset - by default. - -Wed Dec 6 18:51:16 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * server.c (check_password): If user has a null password, then - return 1 if arg is also null. - Reverse sense of return value. Caller changed. - -Wed Dec 6 14:42:57 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * server.c (check_password): new func. - (authenticate_connection): call above new func. - - * login.c (login): use construct_cvspass_filename(). - If CVSroot is not "fully-qualified", then insist the user qualify - it before going on. - (get_cvs_password): fleshed out. Now reads from ~/.cvspass, or - prompts if no appropriate password found. - (construct_cvspass_filename): new func. - - * server.c (authenticate_connection): send ACK or NACK to client. - - * client.c (connect_to_pserver): check for ACK vs NACK response - from server after sending authorization request. - - * login.c (get_cvs_password): new func. - - * client.c (connect_to_pserver): use new func get_cvs_password(). - Prototype it at top of file. Hmmm. - -Wed Dec 6 13:29:22 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * server.c: same as below (AUTH_SERVER_SUPPORT). - - * main.c: same as below (AUTH_SERVER_SUPPORT where appropriate). - - * login.c: same same as below. - - * cvs.h: same as below. - - * client.c: use AUTH_CLIENT_SUPPORT, not CVS_LOGIN. - - * options.h.in (AUTH_CLIENT_SUPPORT, AUTH_SERVER_SUPPORT): these - replace CVS_LOGIN. - -Wed Dec 6 00:04:58 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * server.c (authenticate_connection): expanded comment. - -Tue Dec 5 23:37:39 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (connect_to_pserver): read password from prompt for - now. - - * server.c (authenticate_connection): if the password passes - muster, then don't abort. - -Tue Dec 5 22:46:37 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * subr.c (strip_trailing_newlines): new func. - - * client.c (connect_to_pserver): took out print statements. - - * server.c (authenticate_connection): removed print statments. - Use new func strip_trailing_newlines() to purify `repository', - `username', and `password'. - Run a primitive password check, just for testing. - - * client.c (connect_to_pserver): use CVS_AUTH_PORT. - Take tofdp, fromfdp, and log args. Caller changed. - (get_responses_and_close): either kerberos and CVS_LOGIN might - have one fd for both directions, so adjust #ifdef accordingly. - - * cvs.h (CVS_AUTH_PORT): new define, default to 2401. - Prototype strip_trailing_newlines(). - -Tue Dec 5 16:53:35 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * server.c (authenticate_connection): new func. - - * client.c (init_sockaddr): func moved here from login.c. - (connect_to_pserver): same as above. Take no args, now. - Include <sys/socket.h>, <netinet/in.h>, <netdb.h>, if CVS_LOGIN. - - * cvs.h: Declare use_authenticating_server, as extern int. - Declare connect_to_pserver(). - - * main.c (main): call authenticate_connection(). Removed testing - code. - Add 'a' to the short-option string in the getopt() call. - - * login.c (connect_to_pserver): moved to client.c. - -Tue Dec 5 16:01:42 1995 Peter Chubb <peterc@bookworm.sw.oz.au> - (patch applied by Karl Fogel <kfogel@cyclic.com>) - - * update.c (join_file): if vers->vn_user is "0", file has been - removed on the current branch, so print an error and return. - -Mon Dec 4 14:27:42 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Version 1.6.3. - -Mon Dec 4 16:28:25 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * release.c (release): add return (0) as last line - - * cvs.h: declare program_path - - * main.c define program_path - (main): set program_path - - * release.c (release): use program_path for update_cmd - -Mon Dec 4 11:22:42 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Version 1.6.2. - -Sun Dec 3 20:02:29 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.h (struct rcsnode), rcs.c (freercsnode): Add expand field. - * rcs.h (RCSEXPAND): New #define. - * rcs.c (RCS_reparsercsfile): Record keyword expansion in expand - field of struct rcsnode. - * update.c (checkout_file): Set keyword expansion in Entries file - from rcs file if there is nowhere else to set it from. - * client.c (send_modified, update_entries) [LINES_CRLF_TERMINATED]: - If -kb is in effect, don't convert. - - * update.c (update_file_proc), commit.c (check_fileproc), - rcscmds.c (RCS_merge): Direct stdout to DEVNULL rather than - passing -s option to grep. This avoids trouble with respect to - finding a grep which support -s and whether we should use the (GNU - grep) -q option if it exists. - * options.h.in: Change "@ggrep_path@" to "grep". - -Fri Dec 1 11:53:19 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * rcs.c (RCS_gettag): new parameter return_both force return both - tags: the symbolic and the numeric one. - (RCS_getversion): new parameter return_both is forwarded to - RCS_gettag. - - * rtag.c, tag.c, commit.c, patch.c, update.c: pass 0 as additional - last parameter to RCS_getversion and RCS_gettag - - * rcs.h (RCS_gettag): new parameter return_both. - (RCS_getversion): new parameter return_both. - - * cvs.h (struct vers_ts): add vn_tag slot for symbolic tag name - - * vers_ts.c (Version_TS): call RCS_getversion with 1 for - return_both and split output into vn_rcs and vn_tag - (freevers_ts): free vn_tag - - * update.c (checkout_file): use vn_tag instead of vn_rcs when - calling 'rcs co' to allow rcs expansion of :$Name : - -Thu Nov 30 20:44:30 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (get_responses_and_close): undo previous change - regarding waitpid(). The problem has been solved by modifying - os2/waitpid.c instead of its callers. - -Thu Nov 30 16:37:10 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c: All these changes are for OS/2, which will no longer have - a separate client.c: - (start_kerberos_server): new func, contains code that - used to be in start_server(). - (start_server): moved kerberos code to above function, reorganized - the rest. Added authentication clause. - (call_in_directory): test errno against EACCESS, if EACCESS is - defined (this is for OS/2's oddball mkdir). - (change_mode): don't set execute permission on anything if - EXECUTE_PERMISSION_LOSES is defined. - (get_responses_and_close): if START_RSH_WITH_POPEN_RW, then use - pclose() instead of fclose(). - If waitpid errors with ECHILD, don't die. This is okay. - (start_rsh_server): alternate definition if - START_RSH_WITH_POPEN_RW. - - * main.c: [all these changes conditional on CVS_LOGIN: ] - Don't prototype connect_to_pserver, don't enter it in cmds[] - (actually, it was never in there, I don't know why my previous - change said it was). - (use_authenticating_server): new global var. - (main): if "-a", then set above new var to TRUE. - (usg): document "-a" option. - -Wed Nov 29 12:55:10 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * main.c: Prototype connect_to_pserver(), and enter it in cmds[]. - (main): test some extremely primitive authentication. - - * login.c: Include <sys/socket.h> - (connect_to_pserver): new func. - (init_sockaddr): new func. - -Mon Nov 20 14:07:41 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in (TAGFILES): Separate out from DISTFILES, for C code. - (TAGS,tags): Use TAGFILES not DISTFILES. - -Sun Nov 19 11:22:43 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * recurse.c (do_recursion): Don't call server_pause_check if there - are writelocks around. Revise comment to reflect fact we are no - longer relying on a writelock'd operations being "unable" to - generate enough data to pause. - -Sun Nov 19 10:04:50 1995 Peter Wemm <peter@haywire.DIALix.COM> - - * server.c, server.h, options.h.in: Implement hooks for doing - simple flow control on the server to prevent VM exhaustion on a - slow network with a fast server. - * recurse.c: Call the flow control check at a convenient location - while no locks are active. This is a convenience tradeoff against - accurate flow control - if you have a large directory it will all - be queued up, bypassing the flow control check until the next - directory is processed. - -Sat Nov 18 16:22:06 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c, update.c, vers_ts.c, server.c, rcs.c, lock.c, - ignore.c, entries.c, diff.c, commit.c, checkin.c: - Use new macro `existence_error', instead of comparing errno to - ENOENT directly. - -Fri Nov 17 14:56:12 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (start_server): removed alternate version of this func, - since os2/client.c will now be used under OS/2. - -Thu Nov 16 22:57:12 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (start_server): ifdef HAVE_POPEN_RW, use a different - version of start_server(). This is maybe not the cleanest cut to - make, but it's better than mucking around with yet more #ifdefs in - the middle of the old start_server() function. Once things are - up, I may reposition this code. - -Wed Nov 15 15:33:37 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * main.c (main): ifdef NEED_CALL_SOCKINIT, then call SockInit(). - Only OS/2 needs this initialization. - -Tue Nov 14 18:54:01 1995 Greg A. Woods <woods@most.weird.com> - - * patch.c: - - fix orientation of test for result of getline() call - - use fputs() not printf() when just copying file out - - * cvsbug.sh: - - add space after #! - - new rcs id - - allow version to be edited by Makefile. - - * Makefile.in: - - make Makefile a dependent of all (this might not be perfect, but - it at least gives you a chance to catch up on the second - go-around). - - filter cvsbug.sh in a manner similar to cvsinit.sh to get the - version number set from version.c - -Tue Nov 14 13:28:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Call old log file check.plog, not check.olog. - - * sanity.sh: Convert remaining tests from old-style ('***' on fail - and nothing on pass), to new-style (FAIL on fail and PASS on pass). - - * sanity.sh: Fix ability to run only some of the tests (always run - tests 1-4.75 to set up repository, document better how it works). - - * sanity.sh: Change "completed successfully" to "completed" in - message--many tests, but not all, exit if they fail. - -Tue Nov 14 15:10:00 1995 Greg A. Woods <woods@most.weird.com> - - * sanity.sh: test 63 doesn't work and probably can't - -Tue Nov 14 12:22:00 1995 Greg A. Woods <woods@most.weird.com> - - * sanity.sh: many minor tweaks: - - make the optional arguments almost work - - use a function 'directory_cmp' instead of 'diff -r' - - fix up a few more tests that weren't working.... - -Mon Nov 13 07:33:55 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * cvs.h: ifdef USE_OWN_POPEN, #include "popen.h". Only OS/2 has - its own popen()/pclose() right now. - -Mon Nov 13 04:06:10 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * cvs.h: conform to 80 column standard (yes, I'm a pedant). - -Sat Nov 11 13:45:13 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * client.c (process_prune_candidates): use unlink_file_dir() to - remove the directory, instead of invoking "rm" via run_exec(). - -Fri Nov 10 14:38:56 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * main.c (main): removed "#define KF_GETOPT_LONG 1", since that - change is no longer in testing. - -Thu Nov 9 20:32:12 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * release.c (release): Use Popen(), not popen(). - -Wed Nov 8 10:20:20 1995 Jim Meyering (meyering@comco.com) - - * entries.c (ParseTag): Remove dcl of unused local. - - * patch.c: Include getline.h. - -Wed Nov 8 11:57:31 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * options.h.in: add configuration option STEXID_SUPPORT (default - is off i.e. old semantics) - - * filesubr.c (isaccessable): new function. Checks access-rights - for files like access(), but is getxid-safe. Falls back to - access() if SETXID_SUPPORT is not enabled. - (isfile): replace stat() by isaccessable(file, F_OK) - (isreadable): replace access() by isaccessable() - (iswritable): ditto - (make_directory): rename local variable buf to sb - - * cvs.h: add prototype for new function isaccessable. - - * server.c (serve_root): replace access() by isaccessable() - - * cvsrc.c (read_cvsrc): replace access() by isreadable() - - * main.c (main): replace access() by isaccessable() - -Wed Nov 8 10:22:41 1995 Greg A. Woods <woods@most.weird.com> - - * entries.c (fgetentent): change definition to static to match the - declaration at the top of the file - -Tue Nov 7 16:59:25 1995 J.T. Conklin <jtc@lestat.cygnus.com> - - * rcs.c (RCS_getbranch, RCS_getdate, RCS_getrevtime, RCS_gettag, - RCS_getversion, RCS_head): Use assert() instead of attempting to - "do the right thing" with a bogus RCSNode argument. - -Mon Nov 6 14:24:34 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * vers_ts.c: Remove ctime define. It is just asking for trouble. - -Mon Nov 6 11:58:26 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * vers_ts.c: ifdef ctime, undef it before redefining it. It is a - macro on some systems. - - * lock.c: don't prototype ctime() here. (See note below about - fgetentent() in entries.c.) - -Sun Nov 5 16:06:01 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * entries.c (fgetentent): don't prototype ctime here; we include - cvs.h, which includes system.h, which includes <time.h> - unconditionally (either as <time.h> or <sys/time.h>). Anyway, IBM - C/C++ chokes on mid-function, or even mid-file, prototypes. Sigh. - -Thu Nov 2 21:51:04 1995 Dan Wilder <dan@gasboy.com> - - * rtag.c (rtag): Fix typo ("-T" -> "-F"). - -Tue Oct 31 19:09:11 1995 Dan Wilder <dan@gasboy.com> - - * diff.c (diff_dirproc): just return R_SKIP_ALL if dir not exist. - (diff_file_nodiff): don't complain if file doesn't exist, just - ignore. - -Tue Oct 31 09:25:10 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * sanity.sh: Use absolute pathname for mkmodules. - -Sat Oct 28 01:01:41 1995 Jim Meyering (meyering@comco.com) - - * entries.c (ParseTag): Use getline instead of fgets. - -Fri Oct 27 13:44:20 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * cvs.h: do nothing about alloca ifdef ALLOCA_IN_STDLIB. I am - rather suspicious of this solution, and will not be surprised to - find out that there's a Right Way to handle this situation ("this - situation" being that OS/2 simply declares alloca in <stdlib.h>). - Suggestions are welcome; see src/cvs.h and lib/system.h to see why - I was getting a conflict in the first place. - -Wed Oct 25 16:03:20 1995 J.T. Conklin <jtc@slave.cygnus.com> - - * cvs.h (struct entnode): Add user field. - * entries.c (fputentent): New function, write entries line. - (write_ent_proc): Call fputentent to write entries line. - (Entnode_Create): New function, construct new Entnode. - (Entnode_Destroy): New function, destruct old Entnode. - (AddEntryNode): Changed to take an Entnode argument instead of - separate user, version, timestamp, etc. arguments. - (fgetentent): Changed to return Entnode. - (struct entent, free_entent): Removed. - -Wed Oct 25 12:44:32 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * admin.c (admin): Don't rely on ANSI C string concatenation; - SunOS 4.1.3 /bin/cc doesn't support it. - -Tue Oct 24 22:34:22 1995 Anthony J. Lill <ajlill@ajlc.waterloo.on.ca> - - * import.c (expand_at_signs): Check errno as well as return value - from putc. Some systems bogusly return EOF when successfully - writing 0xff. - -Tue Oct 24 14:32:45 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * admin.c (admin): use getcaller() instead of getpwuid - - * subr.c (getcaller): prefer getlogin() to $USER and $LOGNAME - (especially useful for NT where getuid always returns 0) - -Tue Oct 24 06:22:08 1995 Jim Meyering (meyering@comco.com) - - * cvsrc.c (read_cvsrc): Use getline instead of fgets. - * patch.c (patch_fileproc): Use getline instead of fgets. - - * entries.c (fgetentent): Use getline instead of fgets. - Use xmalloc to allocate space for each returned entry. - Since LINE is no longer static, save it in struct entent. - (struct entent): New member, line. - (free_entent): New function. - (Entries_Open): Call it after each call to fgetentent. - -Tue Oct 24 11:13:15 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * cvs.h: Declare valloc again, but this time with the right - signature (also changed in libs/valloc.c) - -Mon Oct 23 12:17:03 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * logmsg.c (do_editor): Check for errors from stdio calls. - -Mon Oct 23 12:37:06 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h: Don't declare valloc. Some systems (e.g. linux) declare - it in stdlib.h in a conflicting way. - -Mon Oct 23 08:41:25 1995 Jim Meyering (meyering@comco.com) - - * commit.c (commit_filesdoneproc): Use getline instead of fgets. - - * logmsg.c (do_editor): Use getline instead of fgets. - (rcsinfo_proc): Likewise. - - * logmsg.c (do_editor): Lose if fclose of temp file output - stream fails. - -Mon Oct 23 11:59:41 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * cvs.h: add valloc declaration - - * server.h: add server_cleanup prototype - - * server.c: remove server_cleanup prototype - - * mkmodules.c (server_cleanup): fix parameter type - - * server.c: encapsulate wait_sig in #ifdef sun (it's only used in - code which is also encapsulated in #ifdef sun) - - * rcscmds.c (RCS_deltag, RCS_lock): add definition of noerr - parameter - - * error.c: include cvs.h instead of config.h, add USE(rcsid) - - * error.c (error): fix parameter type - - * update.c (join_file): encapsulate recent changes from garyo - within #ifdef SERVER_SUPPORT - -Sun Oct 22 13:47:53 1995 J.T. Conklin <jtc@slave.cygnus.com> - - * client.c (update_entries): Fix memory leak; free mode_string and - file_timestamp. - (send_fileproc): Fix memory leak; call freevers_ts before exiting. - - * module.c (do_module): Partially fix memory leak; added - variable so that the address of memory allocated by line2argv - is retained, but comment out the call to free_names. Freeing - the vector at that point loses because some of the elements - may be used later in the function. - (cat_module): fix memory leak. - - * recurse.c (start_recursion): Fix memory leak; free return - value of Name_Repository after it has been used. - -Sat Oct 21 23:24:26 1995 Jim Meyering (meyering@comco.com) - - * client.c (send_modified) [LINES_CRLF_TERMINATED]: Comment text - after #endif. - -Fri Oct 20 14:41:49 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Add test 87a, to test for bug fixed by garyo in - change below. - -Fri Oct 20 10:59:58 1995 Gary Oberbrunner <garyo@darkstar.avs.com> - - * update.c (join_file): send file back to client even if no - conflicts were detected, by calling Register(). - -Fri Oct 20 10:46:45 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * lock.c: Add prototype for Check_Owner - -Thu Oct 19 16:38:14 1995 Jim Meyering (meyering@comco.com) - - * lock.c (Check_Owner): Declare function `static int'. - -Thu Oct 19 14:58:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * expand_path.c (expand_variable): Fix typo ('*'->'('). - -Thu Oct 19 14:58:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (commit_filesdoneproc): Check for errors from fopen, - fgets, and fclose. - - * rcscmds.c (RCS_merge): Remove comment about rcsmerge -E. - Hacking CVS was never a very good solution; the situation is fixed - in RCS 5.7, and is documented in ../INSTALL. - -Thu Oct 19 15:06:15 1995 Jim Meyering (meyering@comco.com) - - * filesubr.c (xchmod): Parenthesize arithmetic in operand of | - to placate gcc -Wall. - - * expand_path.c (expand_path): Parenthesize assignments used as - truth values to placate gcc -Wall. - - * commit.c (checkaddfile): Remove dcls of unused variables. - * lock.c (unlock): Remove dcl of unused variable. - -Thu Oct 19 14:58:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * root.c (Create_Root): If noexec, don't create CVS/Root. - -Wed Oct 18 11:19:40 1995 J.T. Conklin <jtc@slave.cygnus.com> - - * lock.c (unlock): Change order of comparison so that Check_Owner - is called only if other conditions are true. This performance - enhancement was broken when the AFS support was added. - -Wed Oct 18 12:51:33 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * main.c (main): check if argv[0] is "pserver" with else-if, not - if, since we've already asked if it's "kserver". - -Tue Oct 17 18:09:23 1995 Warren Jones <wjones@tc.fluke.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Deal with supplying a relative cvs filename, or - with a cvs filename which doesn't have basename "cvs". - -Mon Oct 16 15:58:31 1995 Vince Demarco <vdemarco@bou.shl.com> - - * parseinfo.c (Parse_Info): if the Keyword isn't ALL the current - version doesn't use the expanded variable, It should. - -Mon Oct 16 15:58:31 1995 Gary Oberbrunner <garyo@avs.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (server_register): Don't pass NULL to printf if tag, - date, or conflict is NULL. - -Thu Oct 12 12:13:42 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * main.c (main): begin to handle "pserver"; support not complete - yet, however. - -Thu Oct 12 02:52:13 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * expand_path.c: Don't #include <pwd.h>, since cvs.h already does, - and not all systems' <pwd.h>s are protected from multiple inclusion. - * login.c: Likewise. - -Wed Oct 11 15:23:24 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * login.c (login): handle everything correctly now. - -Wed Oct 11 12:02:48 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * rcs.c (RCS_gettag): support RCS keyword Name - -Tue Oct 10 19:11:16 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * options.h.in (CVS_LOGIN): discuss, but leave commented out. - The "cvs login" command is still under construction; however, the - repository was changing so fast that instead of creating a branch - and dealing with the attendant hair, I'm just developing on the - trunk, making sure that everything is surrounded by "#ifdef - CVS_LOGIN ... #endif" so I don't get in anyone's way. - - * login.c: include cvs.h before checking CVS_LOGIN, so it has a - chance to get defined before we ask if it's defined. - (login): oops, use semi not comma in `for' loop init. - - * Makefile.in (SOURCES, OBJECTS): include login.c, login.o. - - * main.c: added protoype for login(). - Added "login" entry to cmds[]. - (usg): added line about "login". - - * login.c: new file. - -Tue Oct 10 18:33:47 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * Makefile.in (COMMON_OBJECTS): added error.o. - (OBJECTS): took error.o out; it's in COMMON_OBJECTS now. - -Tue Oct 10 12:02:37 1995 Thorsten Lockert <tholo@sigmasoft.com> - - * cvsbug.sh: Cater to lame versions of sh (4.4BSD ash) by using - ${foo-bar} instead of `if....`. - -Tue Oct 10 12:02:37 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * remove.c (remove_fileproc): If noexec, don't remove file. Check - for error when removing file. - -Sun Oct 8 12:32:15 1995 Peter Wemm <peter@haywire.DIALix.COM> - - * run.c: detect/use POSIX/BSD style reliable signals for critical - section masking etc. Helps prevent stray locks on interruption. - -Sat Oct 7 23:26:54 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * admin.c (admin): If group CVS_ADMIN_GROUP exists, allow only - users in that group to use "cvs admin". - * options.h.in: Default CVS_ADMIN_GROUP to "cvsadmin". - -Sat Oct 7 23:05:24 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * add.c, checkout.c, commit.c, cvs.h, filesubr.c, import.c, - lock.c, main.c, modules.c, options.h.in: New variable cvsumask - which is used to set mode of files in repository (regardless of - umask in effect when cvs is run). - -Sat Oct 7 22:40:17 1995 Stephen Bailey <sjbailey@sand.npl.washington.edu> - - * lock.c: Include AFSCVS ifdefs to deal with AFS's lack of - correspondance between userid's from stat and from geteuid. - -Sat Oct 7 22:28:49 1995 Scott Carson <sdc@TracerTech.COM> - - * add.c (add): Pass -ko, not -k -ko, to set keyword expansion options. - - * admin.c (admin): Don't skip first argument when sending to server. - -Fri Oct 6 21:45:03 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Version 1.6.1. - -Fri Oct 6 21:31:28 1995 Jeff Johnson <jbj@brewster.jbj.org> - - * cvs.h, admin.c, client.c, commit.c, log.c, modules.c, - parseinfo.c, patch.c, recurse.c, rtag.c, status.c, tag.c: - Prototype when dealing in pointers to functions. - -Fri Oct 6 21:07:22 1995 Mark H. Wilkinson <mhw@minster.york.ac.uk> - - * cvsrc.c (read_cvsrc): fix look up of command names in cvsrc file - to use full name from command table rather than possible nickname - in argv. Fixes errors with things like `cvs di' when cvsrc has - `diff -u5' in it. - -Thu Aug 3 01:03:52 1995 Vince DeMarco <vdemarco@bou.shl.com> - - * parseinfo.c (Parse_Info): Add code to call expand_path function - instead of using built in code. - - * wrapper.c (wrap_add): Add code to call expand_path function to - expand all built in variables. - - * expand_path.c (New file): expand things that look like - environmental variables (only expand local CVS environmental - variables) and user names like ~/. - * cvs.h: Declare expand_path. - - * Makefile.in (SOURCES, OBJECTS): Added expand_path.c, - expand_path.o. - -Fri Oct 6 14:03:09 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * ignore.c (ign_setup): Don't try to look for a file in CVSroot if - client. (The recent tightening of the error checking detects this). - - * commit.c (checkaddfile): Don't try to pass options if it is "". - -Thu Oct 5 18:04:46 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * sanity.sh: unset CVSREAD, since it causes the script to bomb. - -Thu Oct 5 18:29:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * remove.c, add.c, commit.c, cvs.h: Remove CVSEXT_OPT stuff; it - has been broken for ages and the options are already stored in the - Entries file. - -Thu Oct 5 18:20:13 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * commit.c (checkaddfile): New argument options; pass it to RCS. - (commit_fileproc): Pass it. - -Tue Oct 3 09:26:00 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * version.c: upped to 1.6. - -Mon Oct 2 18:10:35 1995 Larry Jones <larry.jones@sdrc.com> - - * server.c: if HAVE_SYS_BSDTYPES_H, include <sys/bsdtypes.h>. - -Mon Oct 2 10:34:53 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * version.c: Upped version to 1.5.95. - -Mon Oct 2 15:16:47 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * tag.c, rtag.c: pass "mov" instead of "add" if tag will be moved - (i.e. invoked with -F) - -Sun Oct 1 18:36:34 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * version.c: upped to 1.5.94. - - * server.c: reverted earlier ISC change (of Sep. 28). - - * version.c: upped to 1.5.93, for Peter Wemm's new SVR4 patch. - -Sun Oct 1 14:51:59 1995 Harlan Stenn <Harlan.Stenn@pfcs.com> - - * main.c: don't #include <pwd.h>; cvs.h does that already. - -Fri Sep 29 15:21:35 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * version.c: upped to 1.5.91 for another pre-1.6 release. - -Fri Sep 29 14:41:14 1995 <bmeier@rzu.unizh.ch> - - * root.c: start rcsid[] with "CVSid". - -Fri Sep 29 13:22:44 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * diff.c (diff): Doc fix. - -Fri Sep 29 14:32:36 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * repos.c (Short_Repository): chop superfluous "/". - - * tag.c (pretag_proc): correct user-visible string. - - * rtag.c (pretag_proc): correct user-visible string. - -Fri Sep 29 13:45:36 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * cvs.h (USE): if __GNUC__ != 2, expand to a dummy var instead of - nothing. - -Thu Sep 28 13:37:05 1995 Larry Jones <larry.jones@sdrc.com> - - * server.c: ifdef ISC, include <sys/bsdtypes.h>. - -Fri Sep 29 07:54:22 1995 Mike Sutton <mws115@llcoolj.dayton.saic.com> - - * filesubr.c (last_component): Don't use ANSI style declaration. - -Wed Sep 27 15:24:00 1995 Del <del@matra.com.au> - - * tag.c, rtag.c: Pass a few extra options to the script - named in taginfo (del/add, and revision number). - - * tag.c: Support a -r option (at long last). Also needs - a -f option to tag the head if there is no matching -r tag. - -Tue Sep 26 11:41:08 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * version.c: Upped version to 1.5.89 for test release preceding - 1.6. - -Wed Sep 20 15:32:49 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * ignore.c (ign_add_file): Check for errors from fopen and fclose. - -Tue Sep 19 18:02:16 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * Makefile.in (DISTFILES): Remove sanity.el from this list; the - file has been deleted. - -Thu Sep 14 14:17:52 1995 Peter Wemm <peter@haywire.dialix.com> - - * import.c: Recover from being unable to open the user file. - - * update.c (join_file): Print a message in the case where the file - was added. - - * mkmodules.c: Deal with .db as well as .pag/.dir (for use with - BSD 4.4 and real dbm support). - -Mon Sep 11 15:44:13 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * release.c (release): Revise comment regarding why and how we - skip argv[0]. - -Mon Sep 11 10:03:59 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * release.c (release): use return value of pclose to determine - success of update. - -Mon Sep 11 09:56:33 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * release.c (release_delete): Fix comment. - -Sun Sep 10 18:48:35 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * release.c (release): made work with client/server. - Don't ask if <arg> is mentioned in `modules'. - -Fri Sep 8 13:25:55 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: When committing a removal, send stdout to LOGFILE; - this is no longer a silent operation. - - * sanity.sh: Remove OUTPUT variable; it is unused. - - * client.c: Add comment regarding deleting temp file. - * main.c: Add comment regarding getopt REQUIRE_ORDER. - -Thu Sep 7 20:24:46 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * main.c (main): use getopt_long(), accept "--help" and - "--version". - Don't assume EOF is -1. - -Thu Sep 7 19:18:00 1995 Jim Blandy <jimb@cyclic.com> - - * cvs.h (unlink_file_dir): Add prototype for this. - -Thu Sep 7 14:38:06 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * ALL FILES: add semicolon, as indicated below. - - * cvs.h (USE): don't provide semicolon in the expansion of the USE - macro; we'd rather the callers provided it themselves because that - way etags doesn't get fooled. - -Mon Sep 4 23:30:41 1995 Magnus Hyllander <mhy@os.se> - - * checkout.c: cvs export now takes -k option and does not default - to -kv. - * checkout.c, cvs.h, modules.c: Modules file now takes -e option - for cvs export. - -Mon Sep 4 23:30:41 1995 Kirby Koster <koster@sctc.com> - - * commit.c: When committing a removal, print a message saying what - we are doing. - -Wed Aug 2 10:06:51 1995 Vince DeMarco <vdemarco@bou.shl.com> - - * server.c: fix compiler warnings (on NeXT) (declare functions as - static inline instead of just static) functions: get_buffer_date, - buf_append_char, and buf_append_data - -Mon Sep 4 22:31:28 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (update_entries), import.c (expand_at_signs): Check for - errors from fread and putc. - -Fri Sep 1 00:03:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Fix TODO item pathname. - - * sanity.el: Removed. It was out of date, didn't do much, and I - doubt anyone was using it. - - * no_diff.c (No_Difference): Don't change the modes of the files. - -Thu Aug 31 13:14:34 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version to 1.5.1. - - * client.c (start_rsh_server): Don't pass -d to "cvs server" - invocation via rsh (restore change which was lost when NT stuff - was merged in). - * sanity.sh: Add TODO item suggesting test for bug which this fixes. - -Wed Aug 30 12:36:37 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * sanity.sh (basic1): Make sure first-dir is deleted before - running this set of tests. - - * subr.c: Extract file twiddling functions to a different file, - because we want to use different versions of many of these - routines under Windows NT. - (copy_file, isdir, islink, isfile, isreadable, iswritable, - open_file, make_directory, make_directories, xchmod, - rename_file, link_file, unlink_file, xcmp, tmpnam, - unlink_file_dir, deep_remove_dir): Moved to... - * filesubr.c: ...this file, which is new. - * Makefile.in (SOURCES): Mention filesubr.c. - (COMMON_OBJECTS): Mention filesubr.o. - - * subr.c: Extract process execution guts to a different file, - because we want to replace these routines entirely under - Windows NT. - (VA_START, va_alist, va_dcl): Move this stuff... - (run_add_arg, run_init_prog): and these declarations... - (run_prog, run_argv, run_argc, run_argc_allocated): and these - variables... - (run_setup, run_arg, run_args, run_add_arg, run_init_prog, - run_exec, run_print, Popen): and these functions... - * run.c: To this file, which is new. - * Makefile.in (SOURCES): Mention run.c. - (COMMON_OBJECTS): Mention run.o. - - * status.c (status): Call ign_setup, if client_active. Otherwise, - we don't end up ignoring CVS directories and such. - - * server.c (mkdir_p, dirswitch): Use CVS_MKDIR instead of mkdir. - - * repos.c (Name_Repository): Use the isabsolute function instead of - checking the first character of the path. - * root.c (Name_Root): Same. - - * release.c (release): Use fncmp instead of strcmp to compare - filenames. - - * rcs.c (RCS_parse, RCS_parsercsfile) [LINES_CRLF_TERMINATED]: - Abort, because we have strong reason to believe this code is - wrong. - - * patch.c (patch): Register signal handlers iff the signal name is - #defined. - - * no_diff.c (No_Difference): Don't try to include server_active in - trace message unless SERVER_SUPPORT is #defined. - - * modules.c (do_module): Use CVS_MKDIR instead of mkdir. - - * mkmodules.c (main): Call last_component instead of writing it out. - - * main.c (main): Call last_component instead of writing it out. - Break up the long copyright string into several strings; Microsoft - Visual C++ can't handle a line that long. Feh. - Use fncmp instead of strcmp to compare filenames. - Register signal handlers iff the signal name is #defined. - - * lock.c (readers_exist): Don't check return value of closedir. - Most of the rest of the code doesn't, and some systems don't - provide a return value anyway. - (set_lock): Use CVS_MKDIR instead of mkdir. - - * import.c (import): Use the isabsolute function instead of - checking the first character of the path. - Try to delete the temporary file again after we close it, so it'll - get deleted on systems that don't let you delete files that are - open. - (add_rev): Instead of making a hard link to the working file and - checking in the revision with ci -r, use ci -u and restore the - permission bits. - (comtable): Include lines from SYSTEM_COMMENT_TABLE, if it is - #defined. - (add_rcs_file) [LINES_CRLF_TERMINATED]: Abort, because we have - strong reason to believe this code is wrong. - (import_descend_dir): Use CVS_MKDIR instead of mkdir. - - * history.c (read_hrecs): Open the file with OPEN_BINARY. - - * find_names.c (add_entries_proc, fsortcmp): Add prototypes. - * entries.c (write_ent_proc): Add prototype. - * hash.c (walklist): Add prototype for PROC argument. - (sortlist): Add prototype for COMP argument. - (printnode): Add a prototype, and make it static. - - * cvs.h (wrap_add_file, wrap_add): Add extern decls for these; - they're used in import.c and update.c. - * wrapper.c (wrap_add_file, wrap_add): Remove them from here. - - * cvs.h (RUN_NORMAL, RUN_COMBINED, RUN_REALLY, RUN_STDOUT_APPEND, - RUN_STDERR_APPEND, RUN_SIGNIGNORE, RUN_TTY, run_arg, run_print, - run_setup, run_args, run_exec, Popen, piped_child, close_on_exec, - filter_stream_through_program, waitpid): Move all these - declarations and definitions to the same section. - - * cvs.h (error_set_cleanup): Fix prototype. - - * cvs.h (isabsolute, last_component): New extern decls. - - * cvs.h (link_file): Function is deleted; remove extern decl. - - * cvs.h (DEATH_STATE, DEATH_SUPPORT): Move #definitions of these - above the point where we #include rcs.h, since rcs.h tests them - (or DEATH_SUPPORT, at least). - - * cvs.h (DEVNULL): #define this iff it isn't already #defined. - config.h may want to override it. - - * cvs.h (SERVER_SUPPORT, CLIENT_SUPPORT): Don't #define these - here; let config.h do that. On some systems, we don't have any - server support. - - * cvs.h: Don't #include <io.h> or <direct.h>; we take care of - those in lib/system.h. - - * commit.c (commit): Open logfile with the OPEN_BINARY flag. - (precommit_proc): Use the isabsolute function, instead of - comparing the first character with /. - (remove_file, checkaddfile): Use CVS_MKDIR instead of mkdir. - - * client.c (send_repository): Use larger line buffers. - - * client.c [LINES_CRLF_TERMINATED] (update_entries): If we've just - received a gzipped file, copy it over, converting LF to CRLF, - instead of just renaming it into place. - [LINES_CRLF_TERMINATED] (send_modified): Convert file to LF format - before sending with gzip. - (send_modified): Don't be disturbed if we get fewer than - sb.st_size characters when we read. The read function may be - collapsing CRLF to LF for us. - - * client.c: Add forward declarations for all the cvs command - functions we call. - - * client.c: Add forward static declarations for all the - handle_mumble functions. - - On some systems, RSH converts LF to CRLF; this screws us up. - * client.c (rsh_pid): Declare this iff RSH_NOT_TRANSPARENT is not - #defined. - (get_responses_and_close): Use SHUTDOWN_SERVER if it is #defined. - Only wait for rsh process to exit if RSH_NOT_TRANSPARENT is not - #defined. - (start_rsh_server): Declare and define only if - RSH_NOT_TRANSPARENT is not #defined. Use piped_child, instead of - writing all that out. - (start_server): Only try to call start_rsh_server if - RSH_NOT_TRANSPARENT is not #defined. Use START_SERVER if it is - #defined. Convert file descriptors to stdio file pointers using - the FOPEN_BINARY_WRITE and FOPEN_BINARY_READ strings. - - * client.h (rsh_pid): Don't declare this; it's never used elsewhere. - (supported_request): Add external declaration for this; - it's used in checkout.c. - - Move process-running functions to run.c; we need to totally - replace these on other systems, like Windows NT. - * client.c (close_on_exec, filter_stream_through_program): Moved - to run.c. - * run.c (close_on_exec, filter_stream_through_program): Here they - are. - - * add.c (add_directory): Use CVS_MKDIR instead of straight mkdir. - * checkout.c (checkout, build_dirs_and_chdir): Same. - (checkout_proc): Use fncmp instead of strcmp. - * client.c (call_in_directory): Use CVS_MKDIR instead of straight - mkdir. - - * client.c (handle_checksum): Cast return value of strtol. - -Wed Aug 30 10:35:46 1995 Stefan Monnier <stefan.monnier@epfl.ch> - - * main.c (main): Allow -d to override CVSROOT_ENV. - -Thu Aug 24 18:57:49 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h, rcscmds.c (RCS_unlock, RCS_deltag, RCS_lock): Add extra - parameter for whether to direct stderr to DEVNULL. - * checkin.c, tag.c, rtag.c, import.c, commit.c: Pass extra - argument. 1 if stderr had been directed to DEVNULL before - rcscmds.c was in use, 0 if it was RUN_TTY. - - * cvs.h: Add comment regarding attic. - -Tue Aug 22 10:09:29 1995 Alexander Dupuy <dupuy@smarts.com> - - * rcs.c (whitespace): Cast to unsigned char in case char is signed - and value is negative. - -Tue Aug 22 10:09:29 1995 Kirby Koster <koster@sctc.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (join_file): If vers->vn_user is NULL, just return. - -Tue Aug 22 10:09:29 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c, client.c: Add comments about modes and umasks. - -Mon Aug 21 12:54:14 1995 Rick Sladkey <jrs@world.std.com> - - * update.c (update_filesdone_proc): If pipeout, don't try to - create CVS/Root. - -Mon Aug 21 12:54:14 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (start_rsh_server): Don't pass -d to "cvs server" - invocation via rsh. - - * server.c (serve_root): Report errors via pending_error_text. - (serve_valid_requests): Check for pending errors. - -Sun Aug 20 00:59:46 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * options.h.in: Document usage of DIFF in update.c - * update.c: Use DIFF -c, not DIFF -u. The small improvement in - diff size is not worth the hassle in terms of everyone having to - make sure that DIFF is GNU diff (IMHO). - -Sat Aug 19 22:05:46 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * recurse.c (start_recursion): Doc fix. - - * server.c (do_cvs_command): Clear error_use_protocol in the - child. - (server): Set error_use_protocol. - -Sun Aug 13 15:33:37 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (do_cvs_command): Don't select on exceptions. - -Fri Aug 4 00:13:47 1995 Jim Meyering (meyering@comco.com) - - * Makefile.in (LDFLAGS): Set to @LDFLAGS@. - (options.h): Depend on ../config.status and options.h.in. - Add rule to build it from dependents. - - * add.c: Include save-cwd.h. - (add_directory): Use save_cwd and restore_cwd instead of - explicit getwd then chdir. - * import.c (import_descend_dir): Likewise. - * modules.c (do_module): Likewise. - - * recurse.c (save_cwd, restore_cwd, free_cwd): Remove functions. - New versions have been broken out into save-cwd.c. - (do_dir_proc): Adapt to handle status code returned by new versions - of save_cwd and restore_cwd -- and one fewer argument to restore_cwd. - (unroll_files_proc): Likewise. - - * wrapper.c (wrap_name_has): Add default: abort () to switch - statement to avoid warning from gcc -Wall. - (wrap_matching_entry): Remove dcl of unused TEMP. - (wrap_tocvs_process_file): Remove dcl of unused ERR. - (wrap_fromcvs_process_file): Likewise. - - * cvs.h: Remove prototype for error. Instead, include error.h. - Also, remove trailing white space. - -Thu Aug 3 10:12:20 1995 Jim Meyering (meyering@comco.com) - - * import.c (import_descend_dir): Don't print probably-bogus CWD - in error messages saying `cannot get working directory'. - -Sun Jul 30 20:52:04 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * parseinfo.c (Parse_Info): Revise comments and indentation. - -Sun Jul 30 15:30:16 1995 Vince DeMarco <vdemarco@bou.shl.com> - - * history.c: put ifdef SERVER_SUPPORT around tracing code incase - the client/server code is not compiled into the program. - -Sat Jul 29 16:59:49 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * subr.c (deep_remove_dir): Use struct dirent, not struct direct. - -Sat Jul 29 18:32:06 1995 Vince DeMarco <vdemarco@bou.shl.com> - - * add.c: Check wrap_name_has. - - * diff.c, checkin.c, import.c: have code call unlink_file_dir in - the appropriate places instead of just calling unlink_file. - - * checkin.c: Remove one unlink call. - - * import.c (comtable): Add .m .psw .pswm. - - * import.c (add_rcs_file): Remove tocvsPath before returning. - - * subr.c (unlink_file_dir): Add new function. unlinks the file if - it is a file. or will do a recursive delete if the path is - actually a directory. - (deep_remove_dir): New function, helps unlink_file_dir. - - * mkmodules.c: Added CVSROOTADM_WRAPPER (cvswrappers file) to the - checkout file list. - -Fri Jul 28 16:27:56 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (safe_location): Use PATH_MAX not MAXPATHLEN. - -Fri Jul 28 19:37:03 1995 Paul Eggert <eggert@twinsun.com> - - * log.c (cvslog, log_fileproc): Pass all options (except -l) - to rlog as-is, so that users can put spaces in options, - can specify multiple -d options, etc. - (ac, av): New variables. - (log_option_with_arg, options): Remove. - - (log_fileproc): Don't prepend `/' to file name if update_dir is empty. - -Tue Jul 25 00:52:26 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (safe_location): Don't use PROTO in function definition. - -Mon Jul 24 18:32:06 1995 Vince DeMarco <vdemarco@bou.shl.com> - - * checkout.c (safe_location): fix a compiler warning. (Declare - safe_location). Changed code in safe_location to call getwd - instead of getcwd. getwd is declared in the ../lib directory and - used exclusively thoughout the code. (this helps portability on - non POSIX systems). - - * wrapper.c: updated Andrew Athan's email address. - - * main.c: fix an ifdef so the code will compile. syntax error in - the ifdef for CVS_NOADMIN. - -Mon Jul 24 13:25:00 1995 Del <del@babel.dialix.oz.au> - - * checkout.c: New procedure safe_location. - Ensures that you don't check out into the repository - itself. - - * tag.c, rtag.c, cvs.h, mkmodules.c: Added a "taginfo" file in - CVSROOT to perform pre-tag checks. - - * main.c, options.h.in: Added a compile time option to - disable the admin command. - -Fri Jul 21 17:07:42 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * update.c, status.c, patch.c, checkout.c, import.c, release.c, - rtag.c, tag.c: Now -q and -Q options just print an error message - telling you to use global -q and -Q options. The non-global - options were a mess because some commands accepted them and some - did not, and they were redundant with -q and -Q global options. - - * rcs.c, cvs.h, commit.c, log.c, find_names.c: Remove CVS.dea - stuff. It is slower than the alternatives and I don't think - anyone ever actually used it. - -Fri Jul 21 10:35:10 1995 Vince DeMarco <vdemarco@bou.shl.com> - - * Makefile.in (SOURCES, OBJECTS): Add wrapper.c, wrapper.o. - * add.c, admin.c, checkout.c, commit.c, diff.c, import.c, log.c, - remove.c, status.c: Call wrap_setup at start of commands. - * add.c (add): Check for wrapper, as well as directory, in repository. - * checkin.c: Add tocvsPath variable and associated handling. - * cvs.h: Add wrapper declarations. - * diff.c: Add tocvsPath variable and associated handling. - * import.c: Add -W option, CVSDOTWRAPPER handling. - (import_descend): check wrap_name_has. - (update_rcs_file, add_rev, add_rcs_file): add tocvsPath - variable and associated handling. - * no_diff.c: Add tocvsPath variable and associated handling. - * recurse.c (start_recursion): Check wrap_name_has. - * update.c: Copy, don't merge, copy-by-merge files. Attempt to - use -j on a copy-by-merge file generates a warning and no further - action. - * update.c: Add CVSDOTWRAPPER handling. - * wrapper.c: Added. - -Fri Jul 21 00:20:52 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * client.c: Revert David Lamkin patch, except for the bits about - removing temp_filename and the .rej file. - * sanity.sh (errmsg1): Test for the underlying bug which Lamkin - kludged around. - * client.c (call_in_directory): Set short_pathname to include the - filename, not just the directory. Improve comments regarding what - is passed to FUNC. - -Thu Jul 20 17:51:54 1995 David Lamkin <drl@net-tel.co.uk> - - * client.c (short_pathname): Fixes the fetching of the whole file - after a patch to bring it up to date has failed: - - failed_patches[] now holds short path to file that failed - - patch temp files are unlinked where the patch is done - -Thu Jul 20 12:37:10 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h: Declare error_set_cleanup - * main.c: Call it. - (error_cleanup): New function. - -Thu Jul 20 12:17:16 1995 Mark H. Wilkinson <mhw@minster.york.ac.uk> - - * add.c, admin.c, checkin.c, checkout.c, classify.c, client.c, - client.h, commit.c, create_adm.c, cvs.h, diff.c, entries.c, - history.c, import.c, log.c, main.c, modules.c, no_diff.c, patch.c, - release.c, remove.c, repos.c, rtag.c, server.c, server.h, - status.c, subr.c, tag.c, update.c, vers_ts.c, version.c: Put - client code inside #ifdef CLIENT_SUPPORT, server code inside - #ifdef SERVER_SUPPORT. When reporting version, report whether - client and/or server are compiled in. - -Wed Jul 19 18:00:00 1995 Jim Blandy <jimb@cyclic.com> - - * subr.c (copy_file): Declare local var n to be an int, - not a size_t. size_t is unsigned, and the return values - of read and write are definitely not unsigned. - - * cvs.h [HAVE_IO_H]: #include <io.h>. - [HAVE_DIRECT_H]: #include <direct.h>. - -Fri Jul 14 22:28:46 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * server.c (dirswitch, serve_static_directory, serve_sticky, - serve_lost, server_write_entries, serve_checkin_prog, - serve_update_prog): Include more information in error messages. - (Thanks, DJM.) - - * cvsbug.sh: Use /usr/sbin/sendmail, unless it doesn't - exist, in which case use /usr/lib/sendmail. (Thanks, DJM.) - - * server.c (server, server_cleanup): Use "/tmp" instead of - "/usr/tmp" when the TMPDIR environment variable isn't set. This - is what the rest of the code uses. - -Thu Jul 13 11:03:17 1995 Jim Meyering (meyering@comco.com) - - * recurse.c (free_cwd): New function. - (save_cwd, restore_cwd): Use it instead of simply freeing any - string. The function also closes any open file descriptor. - - * import.c (comtable): Now static. - (comtable): Put braces around each element of initializer. - - * cvs.h: Add prototype for xgetwd. - * recurse.c (save_cwd, restore_cwd): New functions to encapsulate - run-time solution to secure-SunOS vs. fchown problem. - (do_dir_proc, unroll_files_proc): Use new functions instead of - open-coded fchdir/chdir calls with cpp directives. - - * sanity.sh: Change out of TESTDIR before removing it. - Some versions of rm fail when asked to delete the current directory. - -Wed Jul 12 22:35:04 1995 Jim Meyering (meyering@comco.com) - - * client.c (get_short_pathname): Add const qualifier to parameter dcl. - (copy_a_file): Remove set-but-not-used variable, LEN. - (handle_clear_static_directory): Likewise: SHORT_PATHNAME. - (set_sticky): Likewise: LEN. - (handle_set_sticky): Likewise: SHORT_PATHNAME. - (handle_clear_sticky): Likewise: SHORT_PATHNAME. - (start_rsh_server): Convert perl-style `cond || stmt' to more - conventional C-style `if (cond) stmt.' Sheesh. - Remove dcl of unused file-static, SEND_CONTENTS. - - * history.c: Remove dcls of set-but-not-used file-statics, - HISTSIZE, HISTDATA. - (read_hrecs): Don't set them. - - * import.c (add_rev): Remove dcl of set-but-not-used local, RETCODE. - - * repos.c (Name_Repository): Remove dcl of set-but-not-used local, - HAS_CVSADM. - - * cvsrc.c (read_cvsrc): Parenthesize assignment used as truth value. - -Tue Jul 11 16:49:41 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * hash.h (struct entnode, Entnode): moved from here... - * cvs.h: to here. - -Wed Jul 12 19:45:24 1995 Dominik Westner (dominik@gowest.ppp.informatik.uni-muenchen.de) - - * client.c (server_user): new var. - (parse_cvsroot): set above if repo is "user@host:/dir". - (start_rsh_server): if server_user set, then use it. - -Wed Jul 12 10:53:36 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * sanity.sh: remove the TESTDIR after done. - - * cvsbug.sh (GNATS_ADDR): now bug-cvs@prep.ai.mit.edu again. - -Tue Jul 11 15:53:08 1995 Greg A. Woods <woods@most.weird.com> - - * options.h.in: depend on configure for grep and diff, now that - changes to configure.in are applied. - -Tue Jul 11 14:32:14 1995 Michael Shields <shields@tembel.org> - - * Makefile.in (LDFLAGS): Pick up from configure. - -Tue Jul 11 14:20:00 1995 Loren James Rittle <rittle@supra.comm.mot.com> - - * import.c (add_rev), commit.c (remove_file, ci_new_rev), - checkin.c (Checkin), subr.c (make_message_rcslegal), cvs.h: - Always perform sanity check and fix-up on messages to be passed - directly to RCS via the '-m' switch. RCS 5.7 requires that a - non-total-whitespace, non-null message be provided or it will - abort with an error. CVS is not setup to handle any returned - error from 'ci' gracefully and, thus, the repository entered a - trashed state. - - * sanity.sh: Add regression tests for new code and interactions - with RCS 5.7. - -Sun Jul 9 19:03:00 1995 Greg A. Woods <woods@most.weird.com> - - * .cvsignore: added new backup file - - * options.h.in: our new configure.in finds the right diff and - grep paths now.... - - * subr.c: quote the string in run_print() for visibility - - indent a comment - - Jun Hamano's xchmod() patch to prevent writable files - (from previous local changes) - - * logmsg.c: fix a NULL pointer de-reference - - clean up some string handling code... - (from previous local changes) - - * parseinfo.c: add hack to expand $CVSROOT in an *info file. - - document "ALL" and "DEFAULT" in opening comment for Parse_Info() - - fix the code to match the comments w.r.t. callbacks for "ALL" - - add a line of trace output... - (from previous local changes) - - * mkmodules.c: add support for comments in CVSROOT/checkoutlist - - add CVSroot used by something other .o, ala main.c - (from previous local changes) - - * main.c, cvs.h: add support for $VISUAL as log msg editor - (from previous local changes) - - * status.c: add support for -q and -Q (from previous local changes) - - -Sun Jul 9 18:44:32 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * log.c: trivial change to test ChangeLog stuff. - -Sat Jul 8 20:33:57 1995 Paul Eggert <eggert@twinsun.com> - - * history.c: (history_write): Don't assume that fopen(..., "a") - lets one interleave writes to the history file from different processes - without interlocking. Use open's O_APPEND option instead. - Throw in an lseek to lessen the race bugs on non-Posix hosts. - * cvs.h, subr.c (Fopen): Remove. - - * log.c (log_fileproc): Pass working file name to rlog, so that - the name is reported correctly. - -Fri Jul 7 18:29:37 1995 Michael Hohmuth <hohmuth@inf.tu-dresden.de> - - * client.c, client.h (client_import_setup): New function. - (client_import_done, client_process_import_file): Add comments - regarding now-redundant code. - * import.c (import): Call client_import_setup. - -Tue Jul 4 09:21:26 1995 Bernd Leibing <bernd.leibing@rz.uni-ulm.de> - - * rcs.c (RCS_parsercsfile_i): Rename error to l_error; SunOS4 /bin/cc - doesn't like a label and function with the same name. - -Sun Jul 2 12:51:33 1995 Fred Appelman <Fred.Appelman@cv.ruu.nl> - - * logmsg.c: Rename strlist to str_list to avoid conflict with - Unixware 2.01. - -Thu Jun 29 17:37:22 1995 Paul Eggert <eggert@twinsun.com> - - * rcs.c (RCS_check_kflag): Allow RCS 5.7's new -kb option. - -Wed Jun 28 09:53:14 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in (HEADERS): Remove options.h.in. - (DISTFILES): Add options.h.in. - Depend on options.h in addition to HEADERS. - -Tue Jun 27 22:37:28 1995 Vince Demarco <vdemarco@bou.shl.com> - - * subr.c: Don't try to do fancy waitstatus stuff for NeXT, - lib/wait.h is sufficient. - -Mon Jun 26 15:17:45 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in (DISTFILES): Remove RCS-patches and convert.sh. - -Fri Jun 23 13:38:28 1995 J.T. Conklin (jtc@rtl.cygnus.com) - - * server.c (dirswitch, serve_co): Use CVSADM macro instead of - literal "CVS". - -Fri Jun 23 00:00:51 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * README-rm-add: Do not talk about patching RCS, that only - confuses people. - * RCS-patches, convert.sh: Removed (likewise). - -Thu Jun 22 10:41:41 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * subr.c: Change -1 to (size_t)-1 when comparing against a size_t. - -Wed Jun 21 16:51:54 1995 nk@ipgate.col.sw-ley.de (Norbert Kiesel) - - * create_adm.c, entries.c, modules.c: Avoid coredumps if - timestamps, tags, etc., are NULL. - -Tue Jun 20 15:52:53 1995 Jim Meyering (meyering@comco.com) - - * checkout.c (checkout): Remove dcl of unused variable. - * client.c (call_in_directory, handle_clear_static_directory, - handle_set_sticky, handle_clear_sticky, send_a_repository, - send_modified, send_dirent_proc): Remove dcls of unused variables. - * server.c (receive_file, serve_modified, server_cleanup): - Remove dcls of unused variables. - * subr.c (copy_file): Remove dcl of unused variable. - * vers_ts.c (time_stamp_server): Remove dcl of unused variable. - -Mon Jun 19 13:49:35 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * sanity.sh: Fix commencement message --- the test suite says - "Ok." when it's done. - -Fri Jun 16 11:23:44 1995 Jim Meyering (meyering@comco.com) - - * entries.c (fgetentent): Parenthesize assignment in if-conditional. - -Thu Jun 15 17:33:28 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * server.c (get_buffer_data, buf_append_char, buf_append_data): - Don't conditionalize use of "inline". Autoconf takes care of - defining it away on systems that don't grok it. - -Thu Jun 15 13:43:38 1995 Jim Kingdon (kingdon@cyclic.com) - - * options.h.in (DIFF): Default to "diff" not "diff -a" since diff - might not support the -a option. - -Wed Jun 14 11:29:42 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * import.c (import_descend): Initialize dirlist to NULL. - - * subr.c (copy_file): Fix infinite loop. - - * server.c (serve_directory): fix a memory leak. - - * checkout.c, commit.c, diff.c, history.c, import.c, log.c, - patch.c, release.c, remove.c, rtag.c, status.c, tag.c, update.c: - Use send_arg() to send command line arguments to server. - - * commit.c (fsortcmp), find_names (fsortcmp), hash.c (hashp, - findnode), hash.h (findnode), rcs.c (RCS_addnode, - RCS_check_kflag, RCS_check_tag, RCS_isdead, RCS_parse, - RCS_parsercsfile_i), rcs.h (RCS_addnode, RCS_check_kflag, - RCS_check_tag, RCS_parse): Added const qualifiers as - appropriate. - * rcs.h (RCS_isdead): Added prototype. - - * hash.h (walklist, sortlist): correct function prototypes. - - * ignore.c (ign_setup): don't bother checking to see if file - exists before calling ign_add_file. - -Fri Jun 9 11:24:06 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * all source files (rcsid): Added const qualifer. - * ignore.c (ign_default): Added const qualifier. - * subr.c (numdots): Added const qualifier to function argument. - * cvs.h (numdots): Added const qualifier to prototype argument. - - * client.c (change_mode): Tied consecutive if statements testing - the same variable together with else if. - - * import.c (import_descend): Build list of subdirectories when - reading directory, and then process the subdirectories in that - list. This change avoids I/O overhead of rereading directory - and reloading ignore list (.cvsignore) for each subdirectory. - -Thu Jun 8 11:54:24 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * import.c (import_descend): Use 4.4BSD d_type field if it is - present. - - * lock.c (set_lockers_name): Use %lu in format and cast st_uid - field to unsigned long. - - * import.c (import): Use RCS_check_kflag() to check -k options. - (keyword_usage, str2expmode, strn2expmode, expand_names): - Removed. - * rcs.c (RCS_check_kflag): Added keyword_usage array from import.c - for more descriptive error messages. - - * subr.c (run_setup, run_args): Changed variable argument - processing to work on machines that use <varargs.h>. - - * subr.c (copy_file, xcmp): Changed to read the file(s) by blocks - rather than by reading the whole file into a huge buffer. The - claim that this was reasonable because source files tend to be - small does not hold up in real world situations. CVS is used - to manage non-source files, and mallocs of 400K+ buffers (x2 - for xcmp) can easily fail due to lack of available memory or - even memory pool fragmentation. - (block_read): New function, taken from GNU cmp and slightly - modified. - - * subr.c (xcmp): Added const qualifier to function arguments. - * cvs.h (xcmp): Added const qualifer to prototype arguments. - -Wed Jun 7 11:28:31 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * cvs.h (Popen): Added prototype. - (Fopen, open_file, isreadable, iswritable, isdir, isfile, - islink, make_directory, make_directories, rename_file, - link_file, unlink_file, copy_file): Added const qualifer to - prototype arguments. - * subr.c (Fopen, Popen, open_file, isreadable, iswritable, isdir, - isfile, islink, make_directory, make_directories, rename_file, - link_file, unlink_file, copy_file): Added const qualifier to - function arguments. - - * logmsg.c (logfile_write), recurse.c (do_recursion, addfile): - Don't cast void functions to a void expression. There is at - least one compiler (MPW) that balks at this. - - * rcs.c (keysize, valsize): Change type to size_t. - - * add.c (add_directory): Don't cast umask() argument to int. - - * import.c (add_rcs_file): Changed type of mode to mode_t. - - * rcscmds.c (RCS_merge): New function. - * cvs.h (RCS_merge): Declare. - * update.c (merge_file, join_file): Call RCS_merge instead of - invoking rcsmerge directly. - - * cvs.h: Include <stdlib.h> if HAVE_STDC_HEADERS, otherwise - declared getenv(). - * cvsrc.c, ignore.c, main.c: Removed getenv() declaration. - - * client.c (mode_to_string): Changed to take mode_t instead of - struct statb argument. Simplified implementation, no longer - overallocates storage for returned mode string. - * client.h (mode_to_string): Updated declaration. - * server.c (server_updated): Updated for new calling conventions, - pass st_mode instead of pointer to struct statb. - - * cvs.h (CONST): Removed definition, use of const qualifier is - determined by autoconf. - * history.c, modules.c, parseinfo.c: Use const instead of CONST. - - * add.c, admin.c, checkout.c, commit.c, diff.c, import.c, log.c, - main.c, mkmodules.c, patch.c, recurse.c, remove.c, rtag.c, - server.c, status.c, subr.c, tag.c, update.c: Changed function - arguments "char *argv[]" to "char **argv" to silence lint - warnings about performing arithmetic on arrays. - -Tue Jun 6 18:57:21 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * version.c: Fix up version string, to say that this is Cyclic - CVS. - -Tue Jun 6 15:26:16 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * subr.c (run_setup, run_args, run_add_arg, xstrdup): Add const - qualifier to format argument. - * cvs.h (run_setup, run_args, xstrdup): Likewise. - - * Makefile.in (SOURCES): Added rcscmds.c. - (OBJECTS): Added rcscmds.o. - - * rcscmds.c: New file, with new functions RCS_settag, RCS_deltag, - RCS_setbranch, RCS_lock, RCS_unlock. - * checkin.c, commit.c, import.c, rtag.c, tag.c: Call above - functions instead of exec'ing rcs commands. - * cvs.h: Declare new functions. - -Mon May 29 21:40:54 1995 J.T. Conklin (jtc@rtl.cygnus.com) - - * recurse.c (start_recursion, do_recursion): Set entries to NULL - after calling Entries_Close(). - -Sat May 27 08:08:18 1995 Jim Meyering (meyering@comco.com) - - * Makefile.in (check): Export RCSBIN only if there exists an - `rcs' executable in ../../rcs/src. Before, tests would fail when - the directory existed but contained no executables. - (distclean): Remove options.h, now that it's generated. - (Makefile): Regenerate only *this* file when Makefile.in is - out of date. Depend on ../config.status. - -Fri May 26 14:34:28 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * entries.c (Entries_Open): Added missing fclose(). - (Entries_Close): Don't write Entries unless Entries.Log exists. - - * entries.c (Entries_Open): Renamed from ParseEntries; changed to - process Entries Log files left over from previous crashes or - aborted runs. - (Entries_Close): New function, write out Entries file if - neccessary and erase Log file. - (Register): Append changed records to Log file instead of - re-writing file. - (fgetentent): New function, parse one Entry record from a file. - (AddEntryNode): It's no longer an error for two records with the - same name to be added to the list. New records replace older - ones. - * cvs.h (Entries_Open, Entries_Close): Add prototypes. - (CVSADM_ENTLOG): New constant, name of Entries Log file. - * add.c, checkout.c, client.c, find_names.c, recurse.c: Use - Entries_Open()/Entries_Close() instead of ParseEntries()/dellist(). - - * add.c, admin.c, checkout.c, client.c, commit.c, diff.c, - history.c, import.c, log.c, patch.c, release.c, remove.c, - rtag.c, server.c, status.c, tag.c, update.c: Changed - conditionals so that return value of *printf is tested less than - 0 instead of equal to EOF. - -Thu May 25 08:30:12 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * subr.c (xmalloc): Never try to malloc zero bytes; if the user - asks for zero bytes, malloc one instead. - -Wed May 24 12:44:25 1995 Ken Raeburn <raeburn@cujo.cygnus.com> - - * subr.c (xmalloc): Don't complain about NULL if zero bytes were - requested. - -Tue May 16 21:49:05 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * subr.c (xmalloc): Never try to malloc zero bytes; if the user - asks for zero bytes, malloc one instead. - -Mon May 15 14:35:11 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * lock.c (L_LOCK_OWNED): Removed. - - * add.c, checkout.c, client.c, create_adm.c, cvs.h, entries.c, - find_names.c modules.c, recurse.c, release.c, repos.c, update.c: - removed CVS 1.2 compatibility/upgrade code. - -Mon May 8 11:25:07 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * lock.c (write_lock): Missed one instance where rmdir(tmp) should - have been changed to clear_lock(). - -Wed May 3 11:08:32 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * create_adm.c, entries.c, import.c, root.c: Changed conditionals - so that return value of *printf is tested less than 0 instead of - equal to EOF --- That's all Standard C requires. - -Wed May 3 18:03:37 1995 Samuel Tardieu <tardieu@emma.enst.fr> - - * rcs.h: removed #ifdef CVS_PRIVATE and #endif because cvs didn't - compile anymore. - -Mon May 1 13:58:53 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * rcs.c, rcs.h: Implemented lazy parsing of rcs files. - RCS_parsercsfile_i modified to read only the first two records - of rcs files, a new function RCS_reparsercsfile is called only - when additional information (tags, revision numbers, dates, - etc.) is required. - -Mon May 1 12:20:02 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * Makefile.in (INCLUDES): Include -I. for options.h. - -Fri Apr 28 16:16:33 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * Makefile.in (SOURCES, HEADERS, DISTFILES): Updated. - (dist-dir): Renamed from dist; changed to work with DISTDIR - variable passed from parent. - - We don't want to include a file the user has to edit in the - distribution. - * options.h: No longer distributed. - * options.h.in: Distribute this instead. - * ../INSTALL, ../README: Installation instructions updated. - - * client.c (start_rsh_server): Send the remote command to rsh as a - single string. - -Fri Apr 28 00:29:49 1995 Noel Cragg <noel@vo.com> - - * commit.c: Added initializer for FORCE_CI - - * sanity.sh: Fix tests added 25 Apr -- they were expecting the - server to make noise, but the CVS_SERVER variable had been - accidentally set with the `-Q' flag. Ran all tests -- both - locally and remotely -- to verify that the change didn't break - anything. - -Thu Apr 27 12:41:52 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * Makefile.in: Revise comment regarding check vs. remotecheck. - -Thu Apr 27 12:52:28 1995 Bryan O'Sullivan <bos@cyclic.com> - - * client.c (start_rsh_server): If the CVS_RSH environment variable - is set, use its contents as the name of the program to invoke - instead of `rsh'. - -Thu Apr 27 12:18:38 1995 Noel Cragg <noel@vo.com> - - * checkout.c (checkout): To fix new bug created by Apr 23 change, - re-enabled "expand-module" functionality, because it has the side - effect of setting the checkin/update programs for a directory. To - solve the local/remote checkout problem that prompted this change - in the first place, I performed the next change. - * server.c (expand_proc): Now returns expansions for aliases only. - -Wed Apr 26 12:07:42 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * rcs.c (getrcskey): Rewritten to process runs of whitespace chars - and rcs @ strings instead of using state variables "white" and - "funky". - -Fri Apr 7 15:49:25 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * lock.c (unlock): Only call stat if we need to. - -Wed Apr 26 10:48:44 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (new_entries_line): Don't prototype. - -Tue Apr 25 22:19:16 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * sanity.sh: Add new tests to catch bugs in Apr 23 change. - -Tue Apr 25 17:10:55 1995 Roland McGrath <roland@baalperazim.frob.com> - - * create_adm.c (Create_Admin): Use getwd instead of getcwd. - -Sun Apr 23 20:58:32 1995 Noel Cragg <noel@vo.com> - - * checkout.c (checkout): Disabled "expand-module" functionality on - remote checkout, since it makes modules behave like aliases (see - longer note there). This change necessitated the change below. - Also merged the like parts of a conditional. - - * client.c (call_in_directory): Changed the algorithm that created - nested and directories and the "CVS" administration directories - therein. The algoithm wrongly assumed that the name of the - directory that that was to be created and the repository name were - the same, which breaks modules. - - * create_adm.c (Create_Admin), module.c (do_module), server.c - (server_register), subr.c, entries.c: Added fprintfs for trace-mode - debugging. - - * client.c (client_send_expansions): Argument to function didn't - have a type -- added one. - - * server.c (new_entries_line): Arguments to this function are - never used -- reoved them and fixed callers. - -Sat Apr 22 11:17:20 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * rcs.c (RCS_parse): If we can't open the file, give an error - message (except for ENOENT in case callers rely on that). - -Wed Apr 19 08:52:37 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (send_repository): Check for CVSADM_ENTSTAT in `dir', not - in `.'. - - * sanity.sh: Add TODO list. Revise some comments. Add tests of - one working directory adding a file and other updating it. - -Sat Apr 8 14:52:55 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * Makefile.in (CFLAGS): Let configure set the default for CFLAGS. - Under GCC, we want -g -O. - -Fri Apr 7 15:49:25 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * root.c (Name_Root): merge identical adjacent conditionals. - - * create_admin.c (Create_Admin): Rearranged check for CVSADM and - OCVSADM directories so that CVSADM pathname is only built once. - - * update.c (update_dirleave_proc): Removed code to remove CVS - administration directory if command_name == "export" and to - create CVS/Root file if it is not present. Identical code - in update_filesdone_proc() will perform these same actions. - Also removed code that read and verfied CVS/Root. This is - expensive, and if it is necessary should happen in the - general recursion processor rather than in the update - callbacks. - - * lock.c (masterlock): New variable, pathname of master lockdir. - (set_lock): removed lockdir argument, now constructs it itself - and stores it in masterlock. - (clear_lock): new function, removes master lockdir. - (Reader_Lock, write_lock): call clear_lock instead of removing - master lockdir. - (Reader_Lock, write_lock): #ifdef'd out CVSTFL code. - - * main.c (main): register Lock_Cleanup signal handler. - * lock.c (Reader_Lock, write_lock): no longer register - Lock_Cleanup. - - * main.c (main): initialize new array hostname. - * lock.c (Reader_Lock, write_lock): Use global hostname array. - * logmsg.c (logfile_write): Likewise. - - * recurse.c (do_dir_proc, unroll_files_proc): Use open()/fchdir() - instead of getwd()/chdir() on systems that support the fchdir() - system call. - -Fri Apr 7 06:57:20 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c: Include the word "server" in error message for memory - exhausted, so the user knows which machine ran out of memory. - - * sanity.sh: For remote, set CVS_SERVER to test the right server, - rather than a random one from the PATH. - - * commit.c [DEATH_STATE]: Pass -f to `ci'. - -Thu Apr 6 13:05:15 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * commit.c (checkaddfile): If we didn't manage to fopen the file, - don't try to fclose it. - - * client.c (handle_m, handle_e): Use fwrite, rather than a loop of - putc's. Sometimes these streams are unbuffered. - -Tue Apr 4 11:33:56 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * (DISTFILES): Include cvsbug.sh, ChangeLog, NOTES, RCS-patches, - README-rm-add, ChangeLog.fsf, sanity.sh, sanity.el, and - .cvsignore. - -Mon Mar 27 08:58:42 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * rcs.c (RCS_parsercsfile_i): Accept `dead' state regardless of - DEATH_STATE define. Revise comments regarding DEATH_STATE versus - CVSDEA versus the scheme which uses a patched RCS. - * README-rm-add, RCS-patches: Explain what versions of CVS need - RCS patches. - -Sat Mar 25 18:51:39 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * server.c (server_cleanup): Only do the abysmal kludge of waiting - for command and draining the pipe #ifdef sun. The code makes - assumptions not valid on all systems, and is only there to - workaround a SunOS bug. - -Wed Mar 22 21:55:56 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (mkdir_p): Call stat only if we get the EACCES. Faster - and more elegant. - -Tue Jan 31 20:59:19 1995 Ken Raeburn <raeburn@cujo.cygnus.com> - - * server.c: Try to avoid starting the "rm -rf" at cleanup time - until after subprocesses have finished. - (command_fds_to_drain, max_command_fd): New variables. - (do_cvs_command): Set them. - (command_pid_is_dead): New variable. - (wait_sig): New function. - (server_cleanup): If command_pid is nonzero, wait for it to die, - draining output from it in the meantime. If nonzero SIG was - passed, send a signal to the subprocess, to encourage it to die - soon. - - * main.c (usage): Argument is now `const char *const *'. - * cvs.h (usage): Changed prototype. - (USE): Make new variable `const'. - * add.c (add_usage), admin.c (admin_usage), checkout.c - (checkout_usage, export_usage, checkout), commit.c (commit_usage), - diff.c (diff_usage), history.c (history_usg), import.c - (import_usage, keyword_usage), log.c (log_usage), main.c (usg), - patch.c (patch_usage), release.c (release_usage), remove.c - (remove_usage), rtag.c (rtag_usage), server.c (server), status.c - (status_usage), tag.c (tag_usage), update.c (update_usage): Usage - messages are now const arrays of pointers to const char. - - * import.c (comtable): Now const. - * main.c (rcsid): Now static. - (cmd): Now const. - (main): Local variable CM now points to const. - * server.c (outbuf_memory_error): Local var MSG now const. - - * client.c (client_commit_usage): Deleted. - -Sat Dec 31 15:51:55 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * logmsg.c (do_editor): Allocate enough space for trailing '\0'. - -Fri Mar 3 11:59:49 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * cvsbug.sh: Call it "Cyclic CVS" now, not "Remote CVS". Call it - version C1.4A, not 1.4A2-remote. Send bugs to cyclic-cvs, not - remote-cvs. - - * classify.c (Classify_File): Put check for dead file inside - "#ifdef DEATH_SUPPORT". - -Thu Feb 23 23:03:43 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * update.c (join_file): Don't pass the -E option to rcsmerge here, - either (see Jan 22 change). - -Mon Feb 13 13:28:46 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * cvsbug.sh: Send bug reports to remote-cvs@cyclic.com, rather - than to the ordinary CVS bug address. This does mean we'll have - to wade through GNATS-style bug reports, sigh. - -Wed Feb 8 06:42:27 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * server.c: Don't include <sys/stat.h>; system.h already does, and - 4.3BSD can't take it twice. - - * subr.c [! HAVE_VPRINTF] (run_setup, run_args): Don't use va_dcl - in declaration. Declare the a1..a8 args which are used in the - sprintf call. - * cvs.h [! HAVE_VPRINTF] (run_setup, run_args): Don't prototype - args, to avoid conflicting with the function definitions - themselves. - -Tue Feb 7 20:10:00 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * client.c (update_entries): Pass the patch subprocess the switch - "-b ~", not "-b~"; the latter form seems not to work with patch - version 2.0 and earlier --- it takes the next argv element as the - backup suffix, and thus doesn't notice that the patch file's name - has been specified, thus doesn't find the patch, thus... *aargh* - -Fri Feb 3 20:28:21 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * log.c (log_option_with_arg): New function. - (cvslog): Use it and send_arg to handle the rlog options that take - arguments. The code used to use send_option_string for - everything, which assumes that "-d1995/01/02" is equivalent to - "-d -1 -9 -9 -5 ...". - -Tue Jan 31 15:02:01 1995 Jim Blandy <jimb@floss.life.uiuc.edu> - - * server.c: #include <sys/stat.h> for the new stat call in mkdir_p. - (mkdir_p): Don't try to create the intermediate directory if it - exists already. Some systems return EEXIST, but others return - EACCES, which we can't otherwise distinguish from a real access - problem. - -Sun Jan 22 15:25:45 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * update.c (merge_file): My rcsmerge doesn't accept a -E option, - and it doesn't look too important, so don't pass it. - -Fri Jan 20 14:24:58 1995 Ian Lance Taylor <ian@sanguine.cygnus.com> - - * client.c (do_deferred_progs): Don't try to chdir to toplevel_wd - if it has not been set. - (process_prune_candidates): Likewise. - -Mon Nov 28 09:59:14 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (client_commit): Move guts of function from here... - * commit.c (commit): ...to here. - -Mon Nov 28 15:14:36 1994 Ken Raeburn <raeburn@cujo.cygnus.com> - - * server.c (buf_input_data, buf_send_output): Start cpp directives - in column 1, otherwise Sun 4 pcc complains. - -Mon Nov 28 09:59:14 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (add_prune_candidate): Don't try to prune ".". - -Tue Nov 22 05:27:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c, client.c: More formatting cleanups. - - * client.h, client.c: New variable client_prune_dirs. - * update.c (update), checkout.c (checkout): Set it. - * client.c (add_prune_candidate, process_prune_candidates): New - functions. - (send_repository, call_in_directory, get_responses_and_close): - Call them. - -Wed Nov 23 01:17:32 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * server.c (do_cvs_command): Don't select on STDOUT_FILENO unless - we have something to write. - -Tue Nov 22 05:27:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * remove.c (remove_fileproc): Only call server_checked_in if we - actually are changing the entries file. - - * server.c (server_write_entries): New function. - (dirswitch, do_cvs_command): Call it. - (serve_entry, serve_updated): Just update in-memory data - structures, don't mess with CVS/Entries file. - -Mon Nov 21 10:15:11 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (server_checked_in): Set scratched_file to NULL after - using it. - - * checkin.c (Checkin): If the file was changed by the checkin, - call server_updated not server_checked_in. - -Sun Nov 20 08:01:51 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (send_repository): Move check for update_dir NULL to - before where we check last_update_dir. Check for "" here too. - - * client.c (send_repository): Use new argument dir. - - * client.c: Pass new argument dir to send_repository and - send_a_repository. - - * server.c, server.h (server_prog): New function. - * modules.c (do_modules): Call it if server_expanding. - * client.c: Support Set-checkin-prog and Set-update-prog responses. - * server.c, client.c: Add Checkin-prog and Update-prog requests. - -Fri Nov 18 14:04:38 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (get_short_pathname, is_cvsroot_level, - call_in_directory): Base whether this is new-style or - old-style based on whether we actually used the Directory request, - not based on whether the pathname is absolute. Rename - directory_supported to use_directory. - * server.c: Rename use_relative_pathnames to use_dir_and_repos. - * client.c (send_a_repository): If update_dir is absolute, don't - use it to try to reconstruct how far we have recursed. - - * server.c, server.h, client.c, client.h, vers_ts.c, update.h: - More cosmetic changes (identation, PARAMS vs. PROTO, eliminate - alloca, etc.) to remote CVS to make it more like the rest of CVS. - - * server.c: Make server_temp_dir just the dir name, not the name - with "%s" at the end. - * server.c, client.c: Add "Max-dotdot" request, and use it to make - extra directories in server_temp_dir if needed. - -Thu Nov 17 09:03:28 1994 Jim Kingdon <kingdon@cygnus.com> - - * client.c: Fix two cases where NULL was used and 0 was meant. - -Mon Nov 14 08:48:41 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (serve_unchanged): Set noexec to 0 when calling Register. - - * update.c (merge_file): Don't call xcmp if noexec. - -Fri Nov 11 13:58:22 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (call_in_directory): Deal with it if reposdirname is - not a subdirectory of toplevel_repos. - -Mon Nov 7 09:12:01 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * patch.c: If file is removed and we don't have a tag or date, - just print "current release". - - * classify.c (Classify_File): Treat dead files appropriately. - -Fri Nov 4 07:33:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * main.c (main) [SERVER_SUPPORT]: Move call to getwd past where we - know whether we are the server or not. Set CurDir to "<remote>" - if we are the server. - - * client.c: Remove #if 0'd function option_with_arg. - Remove #if 0'd code pertaining to the old way of logging the - session. - - * client.c (start_rsh_server): Don't invoke the server with the - -d option. - * server.c (serve_root): Test root for validity, just like main.c - does for non-remote CVS. - * main.c (main): If `cvs server' happens with a colon in the - CVSroot, just handle it normally; don't make it an error. - -Wed Nov 2 11:09:38 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (send_dirent_proc): If dir does not exist, just return - R_SKIP_ALL. - - * server.c, client.c: Add Directory request and support for - local relative pathnames (along with the repository absolute - pathnames). - * update.c, add.c, checkout.c, checkin.c, cvs.h, create_adm.c, - commit.c, modules.c, server.c, server.h, remove.c, client.h: - Pass update_dir to server_* functions. Include update_dir in - more error messages. - -Fri Oct 28 08:54:00 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c: Reformat to bring closer to cvs standards for brace - position, comment formatting, etc. - - * sanity.sh: Remove wrong "last mod" line. Convert more tests to - put PASS or FAIL in log file. Change it so arguments to the - script specify which tests to run. - - * client.c, client.h, server.c, checkout.c: Expand modules in - separate step from the checkout itself. - -Sat Oct 22 20:33:35 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com) - - * update.c (join_file): When checking for null return from - RCS_getversion, still do return even if quiet flag is set. - -Thu Oct 13 07:36:11 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (send_files): Call send_repository even if - toplevel_repos was NULL. - - * server.c (server_updated): If joining, don't remove file. - - * update.c (join_file): If server and file is unmodified, check it - out before joining. After joining, call server_updated. New - argument repository. - - * server.c, server.h (server_copy_file): New function. - * update.c (update_file_proc, join_file): Call it. - * client.c (copy_file, handle_copy_file): New functions. - * client.c (responses): Add "Copy-file". - - * client.c, client.h: Make toplevel_wd, failed_patches and - failed_patches_count extern. - * client.c (client_update): Move guts of function from here... - * update.c (update): ...to here. - - * client.c, checkout.c: Likewise for checkout. - - * client.c (is_cvsroot_level): New function. - (handle_set_sticky, handle_clear_sticky, - handle_clear_static_directory): Call it, instead of checking - short_pathname for a slash. - - * client.c, client.h (client_process_import_file, - client_import_done): New functions. - * import.c (import, import_descend): Use them. - * import.c (import_descend): If server, don't mention ignored CVS - directories. - * import.c (import_descend_dir): If client, don't print warm - fuzzies, or make directories in repository. If server, print warm - fuzzies to stdout not stderr. - * client.c (send_modified): New function, broken out from - send_fileproc. - (send_fileproc): Call it. - - * client.c (handle_clear_sticky, handle_set_sticky, - handle_clear_static_directory, handle_set_static_directory): If - command is export, just return. - (call_in_directory, update_entries): If command is export, don't - create CVS directories, CVS/Entries files, etc. - * update.c (update_filesdone_proc): Don't remove CVS directories if - client_active. - - * client.c (send_a_repository): Instead of insisting that - repository end with update_dir, just strip as many pathname - components from the end as there are in update_dir. - - * Makefile.in (remotecheck): New target, pass -r to sanity.sh. - * sanity.sh: Accept -r argument which means to test remote cvs. - - * tag.c (tag), rtag.c (rtag), patch.c (patch), import.c (import), - admin.c (admin), release.c (release): If client_active, connect to - the server and send the right requests. - * main.c (cmds): Add these commands. - (main): Remove code which would strip hostname off cvsroot and try - the command locally. There are no longer any commands which are - not supported. - * client.c, client.h (client_rdiff, client_tag, client_rtag, - client_import, client_admin, client_export, client_history, - client_release): New functions. - * server.c (serve_rdiff, serve_tag, serve_rtag, serve_import, - serve_admin, serve_export, serve_history, serve_release): New - functions. - (requests): List them. - * server.c: Declare cvs commands (add, admin, etc.). - * cvs.h, server.h: Don't declare any of them here. - * main.c: Restore declarations of cvs commands which were - previously removed. - - * cvs.h: New define DEATH_STATE, commented out for now. - * rcs.c (RCS_parsercsfile_i), commit.c (remove_file, checkaddfile) - [DEATH_STATE]: Use RCS state to record a dead file. - -Mon Oct 3 09:44:54 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * status.c (status_fileproc): Now that ts_rcs is just one time, - don't try to print the second time from it. (Same as raeburn 20 - Aug change, it accidentally got lost in 1.4 Alpha-1 merge). - - * cvs.h (CVSDEA): Added (but commented out for now). - * rcs.c (RCS_parsercsfile_i) [CVSDEA]: Also look in CVSDEA to see if - something is dead. - * commit.c (ci_new_rev, mark_file) [CVSDEA]: New functions. - (remove_file, checkaddfile) [CVSDEA]: Use them instead of ci -K. - * find_names.c (find_dirs) [CVSDEA]: Don't match CVSDEA directories. - * update.c (checkout_file): Check RCS_isdead rather than relying - on co to not create the file. - - * sanity.sh: Direct output to logfile, not /dev/null. - - * subr.c (run_exec): Print error message if we are unable to exec. - - * commit.c (remove_file): Call Scratch_Entry when removing tag - from file. The DEATH_SUPPORT ifdef was erroneous. - -Sun Oct 2 20:33:27 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * commit.c (checkaddfile): Instead of calling isdir before - attempting to create the directory, just ignore EEXIST errors from - mkdir. (This removes some DEATH_SUPPORT ifdefs which actually had - nothing to do with death support). - -Thu Sep 29 09:23:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * diff.c (diff): Search attic too if we have a second tag/date. - (diff_fileproc): If we have a second tag/date, don't do all the - checking regarding the user file. - -Mon Sep 26 12:02:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * checkin.c (Checkin): Check for error from unlink_file. - -Mon Sep 26 08:51:10 1994 Anthony J. Lill (ajlill@ajlc.waterloo.on.ca) - - * rcs.c (getrcskey): Allocate space for terminating '\0' if - necessary. - -Sat Sep 24 09:07:37 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * commit.c (commit_fileproc): Set got_message = 1 when calling - do_editor (accidentally omitted from last change). - -Fri Sep 23 11:59:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - Revert buggy parts of Rich's change of 1 Nov 1993 (keeping the - dynamic buffer allocation, which was the point of that change). - * logmsg.c (do_editor): Reinstate message arg, but make it char - **messagep instead of char *message. Change occurances of message - to *messagep. Char return type from char * back to void. - * cvs.h: Change do_editor declaration. - * commit.c: Reinstate got_message variable - (commit_filesdoneproc, commit_fileproc, commit_direntproc): Use it. - * import.c (import), commit.c (commit_fileproc, - commit_direntproc): Pass &message to do_editor; don't expect it to - return a value. - * client.c (client_commit): Likewise. - * import.c (import): Deal with it if message is NULL. - -Wed Sep 21 09:43:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (server_updated): If the file doesn't exist, skip it. - - * diff.c, client.h, client.c: Rename diff_client_senddate to - client_senddate and move from diff.c to client.c. - * client.c (client_update, client_checkout): Use it. - -Sat Sep 17 08:36:58 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * checkout.c (checkout_proc): Don't pass NULL to Register for - version. (should fix "cvs co -r <nonexistent-tag> <file>" - coredump on Solaris). - -Fri Sep 16 08:38:02 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * diff.c (diff_fileproc): Set top_rev from vn_user, not vn_rcs. - Rename it to user_file_rev because it need not be the head of any - branch. - (diff_file_nodiff): After checking user_file_rev, if we have both - use_rev1 and use_rev2, compare them instead of going on to code - which assumes use_rev2 == NULL. - -Thu Sep 15 08:20:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * status.c (status): Return a value in client_active case. - -Thu Sep 15 15:02:12 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * server.c (serve_modified): Create the file even if the size is - zero. - -Thu Sep 15 08:20:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * lock.c (readers_exist): Clear errno each time around the loop, - not just the first time. - - * client.c (start_server): Don't send Global_option -q twice. - - * no_diff.c (No_Difference): Check for error from unlink. - - * no_diff.c, cvs.h (No_Difference): New args repository, - update_dir. Call server_update_entries if needed. Use update_dir - in error message. - * classify.c (Classify_File): Pass new args to No_Difference. - - * server.c (server_update_entries, server_checked_in, - server_updated): Don't do anything if noexec. - - * client.c (send_fileproc): Rather than guessing how big the gzip - output may be, just realloc the buffer as needed. - -Tue Sep 13 13:22:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * lock.c: Check for errors from unlink, readdir, and closedir. - - * classify.c (Classify_File): Pass repository and update_dir to - sticky_ck. - (sticky_ck): New args repository and update_dir. - * server.c, server.h (server_update_entries): New function. - * classify.c (sticky_ck): Call it. - * client.c: New response "New-entry". - * client.c (send_fileproc): Send tag/date from vers->entdata, not - from vers itself. - -Mon Sep 12 07:07:05 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c: Clean up formatting ("= (errno)" -> "= errno"). - - * cvs.h: Declare strerror. - - * client.c: Add code to deal with Set-sticky and Clear-sticky - responses, and Sticky request. - * server.c: Add code to deal with Sticky request. - * server.c, server.h (server_set_sticky): New function. - * create_adm.c (Create_Admin), update.c (update, update_dirent_proc), - commit.c (commit_dirleaveproc): Call it. - * client.c, client.h (send_files): Add parameter aflag. - * add.c (add), diff.c (diff), log.c (cvslog), remove.c (cvsremove), - status.c (status), - client.c (client_commit, client_update, client_checkout): Pass it. - * client.c (client_update): Add -A flag. - -Fri Sep 9 07:05:35 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * entries.c (WriteTag): Check for error from unlink_file. - - * server.c (server_updated): Initialize size to 0. Previously if - the file was zero length, the variable size got used without being - set. - -Thu Sep 8 14:23:05 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (serve_repository): Check for error from fopen on - CVSADM_ENT. - - * update.c (update, update_dirent_proc): Check for errors when - removing Entries.Static. - - * client.c: Add code to deal with Set-static-directory and - Clear-static-directory responses, and Static-directory request. - * server.c, server.h (server_clear_entstat, server_set_entstat): - New functions. - * update.c, checkout.c, modules.c: Call them. - * server.c: Add code to deal with Static-directory request. - - * server.c, client.c: Use strchr and strrchr instead of index and - rindex. - - * server.c (serve_unchanged, serve_lost): Change comments which - referred to changing timestamp; we don't always change the - timestamp in those cases anymore. - -Wed Sep 7 10:58:12 1994 J.T. Conklin (jtc@rtl.cygnus.com) - - * cvsrc.c (read_cvsrc): Don't call getenv() three times when one - time will do. - - * subr.c (xmalloc, xrealloc): Change type of bytes argument from - int to size_t and remove the test that checks if it is less than - zero. - * cvs.h (xmalloc, xrealloc): Update prototype. - -Thu Sep 1 12:22:20 1994 Jim Kingdon (kingdon@cygnus.com) - - * update.c (merge_file, join_file): Pass -E to rcsmerge. - (merge_file): If rcsmerge doesn't change the file, say so. - - * recurse.c, cvs.h (start_recursion): New argument wd_is_repos. - * recurse.c (start_recursion): Use it instead of checking whether - command_name is rtag to find out if we are cd'd to the repository. - * client.c, update.c, commit.c, status.c, diff.c, log.c, admin.c, - remove.c, tag.c: Pass 0 for wd_is_repos. - * rtag.c, patch.c: Pass 1 for wd_is_repos. - - * classify.c, cvs.h (Classify_File): New argument pipeout. - * classify.c (Classify_File): If pipeout, don't complain if the - file is already there. - * update.c, commit.c, status.c: Change callers. - - * mkmodules.c (main): Don't print "reminders" if commitinfo, - loginfo, rcsinfo, or editinfo files are missing. - -Mon Aug 22 23:22:59 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com) - - * server.c (strerror): Static definition replaced by extern - declaration. - -Sun Aug 21 07:16:27 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com) - - * client.c (update_entries): Run "patch" with input from - /dev/null, so if it's the wrong version, it fails quickly rather - than waiting for EOF from terminal before failing. - -Sat Aug 20 04:16:33 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * server.c (serve_unchanged): Instead of creating a file with a - zero timestamp, rewrite the entries file to have "=" in the - timestamp field. - * vers_ts.c (mark_lost, mark_unchanged): New macros. - (time_stamp_server): Use them, for clarity. Interpret "=" - timestamp as an unchanged file. A zero-timestamp file should - never be encountered now in use_unchanged mode. - - * client.c (start_server): If CVS_CLIENT_PORT indicates a - non-positive port number, skip straight to rsh connection. - - * status.c (status_fileproc): Fix ts_rcs reference when printing - version info, to correspond to new Entries file format. Don't - print it at all if server_active, because it won't have any useful - data. - -Thu Aug 18 14:38:21 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * cvs.h (status): Declare. - * client.c (client_status): New function. - - * client.h (client_status): Declare. - * main.c (cmds): Include it. - * server.c (serve_status): New function. - (requests): Add it. - * status.c (status): Do the remote thing if client_active. - - * client.c (supported_request): New function. - (start_server): Use it. - - * server.c (receive_partial_file): New function, broken out from - serve_modified. Operate with fixed-size local buffer, instead of - growing stack frame by entire file size. - (receive_file): New function, broken out from serve_modified. - (serve_modified): Call it. - (server): Print out name of unrecognized request. - - More generic stream-filtering support: - * client.c (close_on_exec, filter_stream_through_program): New - functions. - (server_fd): New variable. - (get_responses_and_close): Direct non-rsh connection is now - indicated by server_fd being non-negative. File descriptors for - to_server and from_server may now be different in case "tee" - filtering is being done. Wait for rsh_pid specifically. - (start_server): Use filter_stream_through_program for "tee" - filter, and enable it for direct Kerberos-authenticated - connections. Use dup to create new file descriptors for server - connection if logging is enabled. - (start_rsh_server): Disable code that deals with logging. - - Per-file compression support: - * cvs.h (gzip_level): Declare. - * main.c (usg): Describe new -z argument. - (main): Recognize it and set gzip_level. - * client.c (filter_through_gzip, filter_through_gunzip): New - functions to handle compression. - (update_entries): If size starts with "z", uncompress - (start_server): If gzip_level is non-zero and server supports it, - issue gzip-file-contents request. - (send_fileproc): Optionally compress file contents. Use a - slightly larger buffer, anticipating the worst case. - * server.c (gzip_level): Define here. - (receive_file): Uncompress file contents if needed. - (serve_modified): Recognize "z" in file size and pass receive_file - appropriate flag. - (buf_read_file_to_eof, buf_chain_length): New functions. - (server_updated): Call them when sending a compressed file. - (serve_gzip_contents): New function; set gzip_level. - (requests): Added gzip-file-contents request. - -Wed Aug 17 09:37:44 1994 J.T. Conklin (jtc@cygnus.com) - - * find_names.c (find_dirs): Use 4.4BSD filesystem feature (it - contains the file type in the dirent structure) to avoid - stat'ing each file. - - * commit.c (remove_file,checkaddfile): Change type of umask - variables from int to mode_t. - * subr.c (): Likewise. - -Tue Aug 16 19:56:34 1994 Mark Eichin (eichin@cygnus.com) - - * diff.c (diff_fileproc): Don't use diff_rev* because they're - invariant across calls -- add new variable top_rev. - (diff_file_nodiff): After checking possible use_rev* values, if - top_rev is set drop it in as well (if we don't already have two - versions) and then clear it for next time around. - -Wed Aug 10 20:50:47 1994 Mark Eichin (eichin@cygnus.com) - - * diff.c (diff_fileproc): if ts_user and ts_rcs match, then the - file is at the top of the tree -- so we might not even have a - copy. Put the revision into diff_rev1 or diff_rev2. - -Wed Aug 10 14:55:38 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * server.c (do_cvs_command): Use waitpid. - - * subr.c (run_exec): Always use waitpid. - - * Makefile.in (CC, LIBS): Define here, in case "make" is run in - this directory instead of top level. - -Wed Aug 10 13:57:06 1994 Mark Eichin (eichin@cygnus.com) - - * client.c (krb_get_err_text): use HAVE_KRB_GET_ERR_TEXT to - determine if we need to use the array or the function. - * main.c: ditto. - -Tue Aug 9 16:43:30 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * entries.c (ParseEntries): If timestamp is in old format, rebuild - it in the new format. Fudge an unmatchable entry that won't - trigger this code next time around, if the file is modified. - - * vers_ts.c (time_stamp): Only put st_mtime field into timestamp, - and use GMT time for it. With st_ctime or in local time, copying - trees between machines in different time zones makes all the files - look modified. - (time_stamp_server): Likewise. - -Tue Aug 9 19:40:51 1994 Mark Eichin (eichin@cygnus.com) - - * main.c (main): use krb_get_err_text function instead of - krb_err_txt array. - -Thu Aug 4 15:37:50 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * main.c (main): When invoked as kserver, set LOGNAME and USER - environment variables to the remote user name. - -Thu Aug 4 07:44:37 1994 Mark Eichin (eichin@cygnus.com) - - * client.c: (handle_valid_requests): if we get an option that has - rq_enableme set, then send that option. If it is UseUnchanged, set - use_unchanged so that the rest of the client knows about - it. (Could become a more general method for dealing with protocol - upgrades.) - (send_fileproc): if use_unchanged didn't get set, send an - old-style "Lost" request, otherwise send an "Unchanged" request. - * server.c (serve_unchanged): new function, same as serve_lost, - but used in the opposite case. - (requests): add new UseUnchanged and Unchanged requests, and make - "Lost" optional (there isn't a good way to interlock these.) - * server.h (request.status): rq_enableme, new value for detecting - compatibility changes. - * vers_ts.c (time_stamp_server): swap meaning of zero timestamp if - use_unchanged is set. - -Tue Jul 26 10:19:30 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * sanity.sh: Separate CVSROOT_FILENAME, which must be the filename - of the root, from CVSROOT, which can include a hostname for - testing remote CVS. (but the tests aren't yet prepared to deal - with the bugs in remote CVS). - - * import.c (update_rcs_file): Change temporary file name in TMPDIR - from FILE_HOLDER to cvs-imp<process-id>. - - * sanity.sh: Add ">/dev/null" and "2>/dev/null" many places to - suppress spurious output. Comment out tests which don't work (cvs - add on top-level directory, cvs diff when non-committed adds or - removes have been made, cvs release, test 53 (already commented as - broken), retagging without deleting old tag, test 63). Now 'make - check' runs without any failures. - -Fri Jul 15 12:58:29 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * Makefile.in (install): Do not depend upon installdirs. - -Thu Jul 14 15:49:42 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c, server.c: Don't try to handle alloca here; it's - handled by cvs.h. - -Tue Jul 12 13:32:40 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (update_entries): Reset stored_checksum_valid if we - quit early because of a patch failure. - -Fri Jul 8 11:13:05 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (responses): Mark "Remove-entry" as optional. - -Thu Jul 7 14:07:58 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * server.c (server_updated): Add new checksum argument. If it is - not NULL, and the client supports the "Checksum" response, send - it. - * server.h (server_updated): Update prototype. - * update.c: Include md5.h. - (update_file_proc): Pass new arguments to patch_file and - server_updated. - (patch_file): Add new checksum argument. Set it to the MD5 - checksum of the version of the file being checked out. - (merge_file): Pass new argument to server_updated. - * client.c: Include md5.h. - (stored_checksum_valid, stored_checksum): New static variables. - (handle_checksum): New static function. - (update_entries): If a checksum was received, check it against the - MD5 checksum of the final file. - (responses): Add "Checksum". - (start_server): Clear stored_checksum_valid. - * commit.c (commit_fileproc): Pass new argument to server_updated. - - * client.h (struct response): Move definition in from client.c, - add status field. - (responses): Declare. - * client.c (struct response): Remove definition; moved to - client.h. - (responses): Make non-static. Initialize status field. - * server.c (serve_valid_responses): Check and record valid - responses, just as in handle_valid_requests in client.c. - - * diff.c (diff_client_senddate): New function. - (diff): Use it to send -D arguments to server. - -Wed Jul 6 12:52:37 1994 J.T. Conklin (jtc@phishhead.cygnus.com) - - * rcs.c (RCS_parsercsfile_i): New function, parse RCS file - referenced by file ptr argument. - (RCS_parsercsfile): Open file and pass its file ptr to above function. - (RCS_parse): Likewise. - -Wed Jul 6 01:25:38 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * client.c (update_entries): Print message indicating that an - unpatchable file will be refetched. - (client_update): Print message when refetching unpatchable files. - -Fri Jul 1 07:16:29 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (send_dirent_proc): Don't call send_a_repository if - repository is "". - -Fri Jul 1 13:58:11 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (last_dirname, last_repos): Move out of function. - (failed_patches, failed_patches_count): New static variables. - (update_entries): If patch program fails, save short_pathname in - failed_patches array, only exit program if retcode is -1, and - return out of the function rather than update the Entries line. - (start_server): Clear toplevel_repos, last_dirname, last_repos. - (client_update): If failed_patches is not NULL after doing first - update, do another update, but remove all the failed files first. - -Thu Jun 30 09:08:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (requests): Add request "Global_option". - (serve_global_option): New function, to handle it. - * client.c (start_server): Deal with global options. Check for - errors from fprintf. - - * client.c (send_fileproc): Split out code which sends repository - into new function send_a_repository. Also, deal with update_dir - being ".". - (send_dirent_proc): Call send_a_repository. - * add.c (add): If client_active, do special processing for - directories. - (add_directory): If server_active, don't try to create CVSADM - directory. - -Thu Jun 30 11:58:52 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (update_entries): If patch succeeds, remove the backup - file. - * server.c (server_updated): Add new argument file_info. If it is - not NULL, use it rather than sb to get the file mode. - * server.h (server_updated): Update prototype for new argument. - * update.c (update_file_proc): Pass new arguments to patch_file - and server_updated. - (patch_file): Add new argument file_info. Don't use -p to check - out new version, check it out into file and rename that to file2. - If result is not readable, assume file is dead and set docheckout. - Call xchmod on file2. Close the patch file after checking for a - binary diff. Set file_info to the results of stat on file2. - (merge_file): Pass new argument to server_updated. - * commit.c (commit_fileproc): Pass new argument to server_updated. - -Wed Jun 29 13:00:41 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (krb_realmofhost): Declare, since it's not the current - <krb.h>. - (start_server): Save the name returned by gethostbyname. Call - krb_realmofhost to get the realm. Pass the resulting realm to - krb_sendauth. Pass the saved real name to krb_sendauth, rather - than server_host. - - * update.c (update_file_proc): Pass &docheckout to patch_file. If - it is set to 1, fall through to T_CHECKOUT case. - (patch_file): Add docheckout argument. Set it to 1 if we can't - make a patch. Check out the files and run diff rather than - rcsdiff. If either file does not end in a newline, we can't make - a patch. If the patch starts with the string "Binary", assume - one or the other is a binary file, and that we can't make a patch. - -Tue Jun 28 11:57:29 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (update_entries): If the patch file is empty, don't run - patch program; avoids error message. - - * classify.c (Classify_File): Return T_CHECKOUT, not T_PATCH, if - the file is in the Attic. - - * cvs.h (enum classify_type): Add T_PATCH. - * config.h (PATCH_PROGRAM): Define. - * classify.c (Classify_File): If user file exists and is not - modified, and using the same -k options, return T_PATCH instead of - T_CHECKOUT. - * update.c (patches): New static variable. - (update): Add u to gnu_getopt argument. Handle it. - (update_file_proc): Handle T_PATCH. - (patch_file): New static function. - * server.h (enum server_updated_arg4): Add SERVER_PATCHED. - * server.c (server_updated): Handle SERVER_PATCHED by sending - "Patched" command. - (serve_ignore): New static function. - (requests): Add "update-patches". - (client_update): If the server supports "update-patches", send -u. - * client.c (struct update_entries_data): Change contents field - from int to an unnamed enum. - (update_entries): Correponding change. If contents is - UPDATE_ENTRIES_PATCH, pass the input to the patch program. - (handle_checked_in): Initialize contents to enum value, not int. - (handle_updated, handle_merged): Likewise. - (handle_patched): New static function. - (responses): Add "Patched". - * commit.c (check_fileproc): Handle T_PATCH. - * status.c (status_fileproc): Likewise. - - * client.c (start_server): If CVS_CLIENT_PORT is set in the - environment, connect to that port, rather than looking up "cvs" in - /etc/services. For debugging. - -Tue Jun 21 12:48:16 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * update.c (joining): Return result of comparing pointer with - NULL, not result of casting (truncating, on Alpha) pointer to int. - - * main.c (main) [HAVE_KERBEROS]: Impose a umask if starting as - Kerberos server, so temp directories won't be world-writeable. - - * update.c (update_filesdone_proc) [CVSADM_ROOT]: If environment - variable CVS_IGNORE_REMOTE_ROOT is set and repository is remote, - don't create CVS/Root file. - * main.c (main): If env var CVS_IGNORE_REMOTE_ROOT is set, don't - check CVS/Root. - -Fri Jun 10 18:48:32 1994 Mark Eichin (eichin@cygnus.com) - - * server.c (O_NDELAY): use POSIX O_NONBLOCK by default, unless it - isn't available (in which case substitute O_NDELAY.) - -Thu Jun 9 19:17:44 1994 Mark Eichin (eichin@cygnus.com) - - * server.c (server_cleanup): chdir out of server_temp_dir before - deleting it (so that it works on non-BSD systems.) Code for choice - of directory cloned from server(). - -Fri May 27 18:16:01 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * client.c (update_entries): Add return type of void. - (get_responses_and_close): If using Kerberos and from_server and - to_server are using the same file descriptor, use shutdown, not - fclose. Close from_server. - (start_server): New function; most of old version renamed to - start_rsh_server. - (start_rsh_server): Mostly renamed from old start_server. - (send_fileproc): Use %lu and cast sb.st_size in fprintf call. - (send_files): Remove unused variables repos and i. - (option_no_arg): Comment out; unused. - * main.c (main): Initialize cvs_update_env to 0. If command is - "kserver", authenticate and change command to "server". If - command is "server", don't call Name_Root, don't check access to - history file, and don't assume that CVSroot is not NULL. - * server.c (my_memmove): Removed. - (strerror): Change check from STRERROR_MISSING to HAVE_STRERROR. - (serve_root): Likewise for putenv. - (serve_modified): Initialize buf to NULL. - (struct output_buffer, buf_try_send): Remove old buffering code. - (struct buffer, struct buffer_data, BUFFER_DATA_SIZE, - allocate_buffer_datas, get_buffer_data, buf_empty_p, - buf_append_char, buf_append_data, buf_read_file, buf_input_data, - buf_copy_lines): New buffering code. - (buf_output, buf_output0, buf_send_output, set_nonblock, - set_block, buf_send_counted, buf_copy_counted): Rewrite for new - buffering code. - (protocol, protocol_memory_error, outbuf_memory_error, - do_cvs_command, server_updated): Rewrite for new buffering code. - (input_memory_error): New function. - (server): Put Rcsbin at start of PATH in environment. - * Makefile.in: Add @includeopt@ to DEFS. - -Fri May 20 08:13:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvs.h, classify.c (Classify_File): New argument update_dir. - Include it in user messages. - * commit.c (check_fileproc), status.c (status_fileproc), update.c - (update_file_proc): Pass update_dir to Classify_File. - * commit.c (check_fileproc), update.c (checkout_file): - Include update_dir in user messages. - * commit.c (check_fileproc) update.c (update_file_proc): Re-word - "unknown status" message. - - * server.c (server_checked_in): Deal with the case where - scratched_file is set rather than entries_line. - - * entries.c (Register): Write file even if server_active. - * add.c (add): Add comment about how we depend on above behavior. - -Tue May 17 08:16:42 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * mkmodules.c: Add dummy server_active and server_cleanup, to go - with the dummy Lock_Cleanup already there. - - * server.c (server_cleanup): No longer static. - -Sat May 7 10:17:17 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - Deal with add and remove: - * commit.c (checkaddfile): If CVSEXT_OPT or CVSEXT_LOG file does - not exist, just silently keep going. - (remove_file): If server_active, remove file before creating - temporary file with that name. - * server.c (serve_remove, serve_add): New functions. - (requests): Add them. - * server.c (server_register): If options is NULL, it means there - are no options. - * server.c, server.h (server_scratch_entry_only): New function. - New variable kill_scratched_file. - (server_scratch, server_updated): Deal with kill_scratched_file. - * commit.c (commit_fileproc): If server_active, call - server_scratch_entry_only and server_updated. - * add.c (add): Add client_active code. - (add): If server_active, call server_checked_in for each file added. - * remove.c (remove): Add client_active code. - (remove_fileproc): If server_active, call server_checked_in. - * main.c (cmds), client.c, client.h: New functions client_add and - client_remove. - * Move declarations of add, cvsremove, diff, and cvslog from - main.c to cvs.h. - * client.c (call_in_directory): Update comment regarding Root and - Repository files. - (send_fileproc): Only send Entries line if Version_TS really finds - an entry. If it doesn't find one, send Modified. - (update_entries): If version is empty or starts with 0 or -, - create a dummy timestamp. - -Thu May 5 19:02:51 1994 Per Bothner (bothner@kalessin.cygnus.com) - - * recurse/c (start_recursion): If we're doing rtag, and thus - have cd'd to the reporsitory, add ,v to a file name before stat'ing. - -Wed Apr 20 15:01:45 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * client.c (client_commit): Call ign_setup. - (client_update, client_checkout): Likewise. - * diff.c (diff): If client, call ign_setup. - * log.c (cvslog): Likewise. - * update.h (ignlist): Change definition to declaration to avoid - depending upon common semantics (not required by ANSI C, and not - the default on Irix 5). - * update.c (ignlist): Define. - -Tue Apr 19 00:02:54 1994 John Gilmore (gnu@cygnus.com) - - Add support for remote `cvs log'; clean up `cvs diff' a bit. - - * client.c (send_arg): Make external. - (send_option_string): New function. - (client_diff_usage): Remove, unused. - (client_diff): Just call diff, not do_diff. - (client_log): Add. - * client.h (client_log, send_arg, send_option_string): Declare. - * cvs.h (cvslog): Declare. - * diff.c (do_diff): Fold back into diff(), distinguish by checking - client_active. - (diff): Remove `-*' arg parsing crud; use send_option_string. - * log.c (cvslog): If a client, start the server, pass options - and files, and handle server responses. - * main.c (cmds): Add client_log. - (main): Remove obnoxious message every time CVS/Root is used. - Now CVS will be quiet about it -- unless there is a conflict - between $CVSROOT or -d value versus CVS/Root. - * server.c (serve_log): Add. - (requests): Add "log". - -Mon Apr 18 22:07:53 1994 John Gilmore (gnu@cygnus.com) - - Add support for remote `cvs diff'. - - * diff.c (diff): Break guts out into new fn do_diff. - Add code to handle starting server, writing args, - sending files, and retrieving responses. - (includes): Use PARAMS for static function declarations. - * client.c (to_server, from_server, rsh_pid, - get_responses_and_close, start_server, send_files, - option_with_arg): Make external. - (send_file_names): New function. - (client_diff): New function. - * client.h (client_diff, to_server, from_server, - rsh_pid, option_with_arg, get_responses_and_close, start_server, - send_file_names, send_files): Declare. - * cvs.h (diff): Declare. - * main.c (cmds): Add client_diff to command table. - * server.c (serve_diff): New function. - (requests): Add serve_diff. - (server): Bug fix: avoid free()ing incremented cmd pointer. - * update.h (update_filesdone_proc): Declare with PARAMS. - -Sat Apr 16 04:20:09 1994 John Gilmore (gnu@cygnus.com) - - * root.c (Name_root): Fix tyop (CVSroot when root meant). - -Sat Apr 16 03:49:36 1994 John Gilmore (gnu@cygnus.com) - - Clean up remote `cvs update' to properly handle ignored - files (and files that CVS can't identify), and to create - CVS/Root entries on the client side, not the server side. - - * client.c (send_fileproc): Handle the ignore list. - (send_dirent_proc): New function for handling ignores. - (send_files): Use update_filesdone_proc and send_dirent_proc - while recursing through the local filesystem. - * update.h: New file. - * update.c: Move a few things into update.h so that client.c - can use them. - -Fri Mar 11 13:13:20 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * server.c: If O_NDELAY is not defined, but O_NONBLOCK is, define - O_NDELAY to O_NONBLOCK. - -Wed Mar 9 21:08:30 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - Fix some spurious remote CVS errors caused by the CVS/Root patches: - * update.c (update_filesdone_proc): If server_active, don't try to - create CVS/Root. - * root.c (Name_Root): Make error messages which happen if root is - not an absolute pathname or if it doesn't exist a bit clearer. - Skip them if root contains a colon. - -Mon Nov 1 15:54:51 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * client.c (client_commit): dynamically allocate message. - -Tue Jun 1 17:03:05 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) - - * server.h: remove alloca cruft - - * server.c: replace with better alloca cruft - -Mon May 24 11:25:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com) - - * entries.c (Scratch_Entry): Update our local Entries file even if - server_active. - - * server.c (server_scratch, server_register): If both Register - and Scratch_Entry happen, use whichever one happened later. - If neither happen, silently continue. - - * client.c (client_checkout): Initialize tag and date (eichin and - I independently discovered this bug at the same time). - -Wed May 19 10:11:51 1993 Mark Eichin (eichin@cygnus.com) - - * client.c (update_entries): handle short reads over the net - (SVR4 fread is known to be broken, specifically for short - reads off of streams.) - -Tue May 18 15:53:44 1993 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (do_cvs_command): Fix fencepost error in setting - num_to_check. - - * server.c (do_cvs_command): If terminated with a core dump, print - message and set dont_delete_temp. - (server_cleanup): If dont_delete_temp, don't delete it. - - * client.c (get_server_responses): Don't change cmd since we - are going to "free (cmd)". - - * server.c: Rename memmove to my_memmove pending a real fix. - - * server.c (do_cvs_command): Set num_to_check to largest descriptor - we try to use, rather than using (non-portable) getdtablesize. - -Wed May 12 15:31:40 1993 Jim Kingdon (kingdon@lioth.cygnus.com) - - Add CVS client feature: - * client.{c,h}: New files. - * cvs.h: Include client.h. - * main.c: If CVSROOT has a colon, use client commands instead. - * vers_ts.c (Version_TS): If repository arg is NULL, don't worry - about the repository. - * logmsg.c (do_editor): If repository or changes is NULL, just don't - use those features. - * create_adm.c (Create_Admin), callers: Move the test for whether - the repository exists from here to callers. - * repos.c (Name_Repository): Don't test whether the repository exists - if client_active set (might be better to move test to callers). - - Add CVS server feature: - * server.{c,h}: New files. - * cvs.h: Include server.h. - * checkin.c (Checkin): Call server_checked_in. - * update.c (update_file_proc, merge_files): Call server_updated. - * entries.c (Register): Call server_register. - (Scratch_Entry): Call server_scratch. - * main.c: Add server to cmds. - * vers_ts.c (Version_TS): If server_active, call new function - time_stamp_server to set ts_user. - - -For older changes, there might be some relevant stuff in the bottom of -the NEWS file, but I'm afraid probably a lot of them are lost in the -mists of time. diff --git a/contrib/cvs/src/ChangeLog-96 b/contrib/cvs/src/ChangeLog-96 deleted file mode 100644 index 6c3a2a1..0000000 --- a/contrib/cvs/src/ChangeLog-96 +++ /dev/null @@ -1,4434 +0,0 @@ -Mon Dec 30 15:43:48 1996 Abe Feldman <feldman@harvey.cyclic.com> - - * checkout.c (build_dirs_and_chdir): Reproduced block containing - Create_Admin, placing it before Subdir_Register. - * sanity.sh (basicb): Added tests 1a and 9a to test above changes - to the checkout command. - -Mon Dec 30 13:29:14 1996 uz@wuschel.ibb.schwaben.com (Ullrich von Bassewitz) - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h (CVSEDITPREFIXLEN): New define. - * logmsg.c (do_editor): Use CVSEDITPREFIXLEN when deciding whether - to strip off CVSEDITPREFIX and when telling the user what we will - strip off. - -Sun Dec 22 22:06:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * logmsg.c (do_verify): If noexec, skip the verification *without* - printing a message. Use cvs_output not printf. Skip verification - for client_active. - -Wed Dec 18 12:27:35 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * repos.c (Name_Repository): Add comment regarding wording of - "*PANIC*" error message. - -1996-12-18 Jim Kingdon - - * client.c (call_in_directory): If the directory we are about - to create is the same as CVSADM as seen by fncmp (for example, - it is "cvs" and filenames are case-insensitive), then give a - fatal error. - -Tue Dec 17 13:14:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * options.h.in: Add comments about SETXID security holes. - - * logmsg.c (do_verify): Reindent comments. Check errno if return - code from run_exec is -1, not if it is 1. - * sanity.sh (info): Move tests info-4 and info-8 to end and rename - them. Add verifymsg tests. Instead of forcibly removing loginfo, - remove it nicely (test info-11). - -Tue Dec 17 12:45:32 1996 Abe Feldman <feldman@cyclic.com> - - * commit.c, import.c: Call do_verify as well as do_editor. - * cvs.h (CVSROOTADM_VERIFYMSG): Define. - * logmsg.c, cvs.h (do_verify, verifymsg_proc): New functions. - (verifymsg_script): New variable. - * mkmodules.c (filelist): Add CVSROOTADM_VERIFYMSG. - -Mon Dec 16 13:24:47 1996 Ian Lance Taylor <ian@cygnus.com> - - * lock.c (remove_locks): New static function, copied from part of - Lock_Cleanup. - (Lock_Cleanup): Call remove_locks. - (Writer_Lock): Call remove_locks rather than Lock_Cleanup when - waiting for a lock. - -Thu Dec 12 10:36:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * login.c (get_cvs_password): If CVS_PASSWORD is set, print a - warning (and then proceed to ignore it). It was a documented - feature, so we should point people who were using it to the - replacement. - -Mon Dec 9 12:35:43 1996 Ian Lance Taylor <ian@cygnus.com> - - * server.c (server_updated): Change comment to only worry about - umask in the rsh case. - (server): Create the temporary directory, and change the mode to - S_IRWXU. - (switch_to_user): Set the umask to 0, not 077. - -Mon Dec 9 10:58:28 1996 Jim Blandy <jimb@floss.cyclic.com> - - * login.c (get_cvs_password): Remove code to check for value of - CVS_PASSWORD. Keeping cleartext passwords in environment - variables is a really bad idea on Unix, since anyone can print - out a processes' environment using 'ps' (on BSD variants - anyway). Update help message. - -Fri Dec 6 15:59:40 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: When matching "use .cvs commit. to remove this file - permanently" messages, change "cvs" to "${PROG}". - (rdiff, binfiles): Likewise. - This fixes testing a program named something other than "cvs", e.g. - $ cp cvs cvs-test - $ /bin/sh <srcdir>/sanity.sh `pwd`/cvs-test - -1996-12-02 Jim Kingdon - - * client.c: In comment saying that socket buffers don't - implement the blocking routine, say they are blocking. - * buffer.h (struct buffer): In description of input function, - describe blocking, non-blocking, and NEED more fully. Say - what happens if we read a nonzero amount less than NEED and - then get end of file. - * client.c (socket_buffer_input): If NEED == 0, still call - recv (once). Handle the case where recv returns 0. - -Sat Nov 30 15:10:07 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * subr.c, cvs.h (file_has_markers): New function. - * rcs.h (RCS_MERGE_PAT): Now a fixed string not a regexp. - * options.h.in (GREP): Removed; no longer used. - * update.c (update_fileproc), commit.c (check_fileproc): Call - file_has_markers rather than GREP. - * rcscmds.c (RCS_merge): Just give a fatal error in the case where - we had been calling GREP. I suspect noone is using this code - any more. - * sanity.sh (conflicts): Rewrite tests 131, 132, and 133 to use - dotest; tests that the above changes didn't break anything. - -Fri Nov 29 09:06:41 1996 fnf@ninemoons.com (Fred Fish) - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (safe_location): Only call readlink if HAVE_READLINK. - - * run.c (piped_child, filter_stream_through_program): If - HAVE_VFORK, call vfork not fork. - * run.c (run_exec): Add comment about why we use vfork. - -Mon Nov 25 12:48:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * release.c (release): Don't return after processing the first - argument; that kind of defeats the purpose of having a loop, eh? - For client, close the connection after we've processed them all. - * sanity.sh: Remove workaround for modules2-8 test; tests for - above fix. Adjust modules2-6 test to answer both questions. - - * login.c: Reindent (all of get_cvs_password, a handful of lines - elsewhere). - - Cleanups to release, mostly cosmetic: - * release.c (release_server): New function; breaks out server code - from the release function. - * release.c: Move delete_flag inside the release function. - * release.c (release): Reindent. Rewrite comments about how the - implementation could be improved. Don't declare variables as - "register". Include errno in error message. Don't cast result of - printf to void. Remove unused variable srepos. - * release.c: Remove comments at top of file about what it does. - They were not particularly coherent and they were also out of date - (I think). Likewise for comment in release function about "if we - are in a repository". - * release.c: Change "module" to "directory" in a few messages - since that is what is meant. - * sanity.sh: In tests ignore-195 and ignore-193, change expected - message accordingly. - -Sun Nov 24 11:30:55 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Clarify a few items in the todo list. - - * log.c (log_parse_date): Use the "end" of the epoch not "next - week" as the time which means "no end time". - * sanity.sh (rcs): New test, tests dates and importing RCS files. - -1996-11-19 Jim Kingdon - - Visual C++ lint: - * hash.c: Declare qsort_comp. - * update.c: Declare isremoved. - -1996-11-19 Jim Kingdon <kingdon@harvey.cyclic.com> - - * root.c, repos.c, modules.c, create_adm.c: Change all calls to - strip_path to strip_trailing_slashes. Basically strip_path is - just an unneeded complication (we should keep the pathname the way - the user specifies it, and the system can worry about things like - consecutive /'s if it wants to). Stripping trailing slashes is - potentially dubious for the same reason, but it is a somewhat - different case which I won't try to tackle now. - * cvs.h (strip_path): Remove declaration. - -Tue Nov 19 15:18:13 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - There are a lot of details to this change, but the concept is - relatively simple: make it so that for every CVSLCK lock that we - might take out, there is a flag which is set iff we have created - the CVSLCK directory. - * lock.c (struct lock): New structure. - * lock.c: Remove static variables repository and cleanup_lckdir. - They are replaced by global_readlock.repository and - global_readlock.have_lckdir, respectively (except insofar as the - rest of these changes change the concept of cleanup_lckdir). - New static variable global_readlock. - (Reader_Lock, Lock_Cleanup): Use global_readlock in place of - repository. - (lock_simple_remove, set_lock, clear_lock, write_lock): Take a - struct lock * instead of just a repository. Set/clear - lock->have_lckdir instead of cleanup_lckdir. - (set_writelock_proc, unlock_proc): Pass ->data, not ->key, to - write_lock or lock_simple_remove. - (lock_filesdoneproc,lock_dir_for_write): Allocate a struct lock, - put it in the ->data field, and fill in its fields. - (lock_simple_remove): Use lock->have_lckdir as the sole test for - whether the CVSLCK directory needs to be removed. Add - comments about why readlock and writelock variables don't tell us - for sure whether locks exist. - (lock_simple_remove, clear_lock): Use SIG_beginCrSect and - SIG_endCrSect to ensure that ->have_lckdir is set to 0 iff the - CVSLCK directory was really removed. - (lock_simple_remove): Check for errors removing CVSLCK directory. - (lock_simple_remove, Check_Owner, set_lock): Remove all code which - checks userids (including all of Check_Owner and all the AFCVS - code). It was bogus if several CVS processes with the same userid - were running (common if several users share a userid; a common - practice with remote CVS), and with the rest of the changes here - should not be needed. - -1996-11-16 Paul Eggert <eggert@twinsun.com> - - * rcs.c (RCS_deltas): Fix unintended trigraphs. - -Fri Nov 15 13:06:03 1996 Tom Hageman <tom@basil.icce.rug.nl> - - * diff.c (diff_fileproc): In printing error messages, use the - correct filename for which the error occurred. - -Sun Nov 10 21:13:38 1996 Paul Sanders <p.sanders@dial.pipex.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c: Use all the right cruft which goes along with - including sys/time.h. - - * server.c: Include a "copyright" notice. - - * server.c: If HAVE_WINSOCK_H, include winsock.h. - - * server.c (server): Only set a handler for SIGHUP if it is - defined. Likewise for all the other signals. - - * server.c (do_cvs_command): Use DEVNULL not /dev/null. - -Fri Nov 08 12:14:20 1996 Jim Kingdon - - IBM ICC (OS/2) lint: - * add.c (add): Only declare begin_added_files if - SERVER_SUPPORT. - * client.c (init_sockaddr): Change port argument from - unsigned short to unsigned int. Change hostname - argument from const char * to char *. - -Sun Nov 3 18:24:28 1996 Noel Cragg <noel@gargle.rain.org> - - * sanity.sh (info): add new tests that check behavior of format - string substitution in loginfo file. - -Sat Nov 2 09:39:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (do_deferred_progs): Don't access memory once it is - freed (we already did it right for checkin_progs; do the same - thing for update_progs). - - * update.c, client.c, classify.c, client.h, diff.c, commit.c, - create_adm.c: Nuke more PATH_MAX. - -Fri Nov 1 18:22:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * error.h: Define PROTO if it is not defined. - -Wed Oct 30 08:53:20 1996 jalving@ibm.net - - * patch.c (patch_fileproc): Set line1 and line2 to NULL up-front - (before the first "goto out") so we don't try to free them. - -Wed Oct 30 08:53:20 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (remove_file, commit_filesdoneproc), run.c (run_print, - run_exec), modules.c (open_module, cat_module, do_module), update.c - (update_dirleave_proc), tag.c (tag_fileproc): Call cvs_out* rather - than stdio. - * server.c (serve_expand_modules): Remove comment about do_module - writing to stdout/stderr; above changes should fix this. - -Tue Oct 29 17:23:59 1996 Ian Lance Taylor <ian@cygnus.com> - - * status.c (tag_list_proc): When printing the tag name, don't - truncate it to 25 characters. - -Tue Oct 29 12:49:07 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c, checkin.c, checkout.c, filesubr.c: Nuke arbitrary limit - of PATH_MAX. Many more such limits surely remain. - - * fileattr.c (fileattr_set): Set attrs_modified *after* we might - call fileattr_read, because fileattr_read clears it. - * sanity.sh (devcom2): New tests, test for above fix and other - behaviors I discovered in the process of looking into it. - -Mon Oct 28 08:55:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - The following changes are to ensure that SYSTEM_CLEANUP is always - called. - * error.c, cvs.h, main.c: Remove error_set_cleanup and related - machinery. It was for a time when error.c was intended to be - shared with other programs, but that is no longer true. - * error.c, error.h (error_exit): New function; like error_cleanup - from main.c but also calls SYSTEM_CLEANUP and exit (EXIT_FAILURE). - * error.c (error, fperror): Call error_exit instead of doing it - ourself. - * server.c (server, serve_valid_responses, switch_to_user, - check_password, pserver_authenticate_connection, - kserver_authenticate_connection): Call SYSTEM_CLEANUP before exit. - * add.c, client.c, import.c, main.c, mkmodules.c, modules.c, - recurse.c, server.c, tag.c, update.c: Call error_exit () - instead of exit (EXIT_FAILURE). - -Sun Oct 27 08:34:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (conflicts): New test 128.5 tests "cvs co -p" in an empty - directory (like 126.5), but when the file has nonempty contents. - * rcs.c (RCS_checkout): If writing to stdout, use cvs_output - rather than fwrite. - * update.c (checkout_file): Call cvs_stderr not fprintf. - These changes should fix some out-of-order bugs which show up in - situations like conflicts-126.5 and conflicts-128.5. - - * mkmodules.c (checkout_file): Call RCS_checkout rather than - run_exec on RCS_CO. - -Sat Oct 26 18:29:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (rdiff): cd out of testimport directory and remove it - when done. - - * sanity.sh (info): Adjust tests to reflect fact that loginfo was - created by cvs init. - - * sanity.sh (ignore): Change test 187a1 to allow any number of - files in CVSROOT, not just modules. - - * sanity.sh (modules): In tests 148a0 and 148a1, don't expect a - module which defines CVSROOT to itself, since we don't define one - any more. Also change test to rewrite modules rather than append - to it (in case any previous tests are changed to do something with - modules). Change test 155b to allow any number of files in - CVSROOT, not just modules. - - * add.c (add_directory): Set rev_old and rev_new fields of struct - logfile_info to NULL (prevents us from trying to free them later). - * commit.c (find_fileproc), import.c (import): Likewise. - - * sanity.sh (crerepos): New tests, to test alternate ways of - creating a repository and related matters. - * sanity.sh: Remove tests 1 through 3 and related cruft; replace - them with a new test 1 which merely tests "cvs init". By doing - the obscure stuff in crerepos we avoid having to do all this stuff - any time we run any single test. - -Sat Oct 26 16:19:48 1996 Jim Blandy <jimb@totoro.cyclic.com> - - * main.c (main): If HAVE_TZSET is #defined, call tzset. This is - harmless on all systems I know of, and required on some. - -Fri Oct 25 13:20:44 1996 Ian Lance Taylor <ian@cygnus.com> - - * diff.c (diff_file_nodiff): When setting use_rev1, only return - DIFF_SAME if empty_file is DIFF_DIFFERENT and ts_user is not - NULL. Don't get confused by a vn_user field of "0" or one - starting with '-'. - * sanity.sh (death2): Add new death2-diff-{1,2,7,8} tests for - above patch. Renumber existing death2-diff tests to make room. - -Fri Oct 25 12:38:29 1996 Jim Wilson <wilson@cygnus.com> - - * sanity.sh (death2): In tests death2-diff-{2,4,6,8,10}, allow "_" - in temp file names. The system (tmpnam or whatever) generates - these names so they vary from system to system. - -Fri Oct 25 07:52:44 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * logmsg.c (logfile_write): Give an error for several cases which - should not be legal. Adjust comments accordingly. - * mkmodules.c (loginfo_contents): Make description of loginfo much - more concise. This should be a reminder, not full documentation. - -Tue Oct 22 10:37:37 1996 Noel Cragg <noel@gargle.rain.org> - - * commit.c (update_delproc): free structure members rev_old and - rev_new if they have been allocated. - - * mkmodules.c: change loginfo_contents to include a description of - the new format string. - - * logmsg.c (logfile_write): change syntax of format string. - -Sat Oct 19 16:09:55 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - For reference, this takes CVS's text segment from 348348 bytes to - 347420 bytes. - * server.c (requests): Change Directory to rq_essential - per change in doc/cvsclient.texi. - * client.c: Remove use_directory and all code which executed if - it wasn't set. This includes the get_short_pathname function. - * server.c: Likewise, for use_dir_and_repos. - (serve_repository): Give a fatal error. - * server.c (requests): Remove Lost. Change Unchanged to rq_essential. - (serve_lost): Removed. - * server.c, server.h, client.c, vers_ts.c: Remove use_unchanged, - code to set it, and all code which executed if it wasn't set. - -Sat Oct 19 12:44:08 1996 J. Richard Sladkey <jrs@world.std.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * hash.c (sortlist, new function qsort_comp): Rewrite to use qsort - instead of insert sort. Changes algorithm from n^2 to n log n - (assuming qsort is implemented with quicksort or similar). - -Sat Oct 19 12:44:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basic2): In test basic2-64, use -x and specify types - which exclude E; the test is not built to deal with E (or any - other new types). - -Sat Oct 19 12:00:00 1996 Mark Mitchell <mmitchell@usa.net> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (isemptydir, new function isremoved): Avoid pruning - directories that contain files marked for removal but not - comitted. - * update.c, update.h (isemptydir): Now extern, not static. - * update.c (isemptydir): New parameter might_not_exist handles - difference in functionality from old client_isemptydir. Bring - over the improved error checking from client_isemptydir. - * client.c (client_isemptydir): Removed; isemptydir now suffices. - * update.c (update_dirleave_proc), client.c - (process_prune_candidates): Update callers. - * sanity.sh (deep): Add tests deep-rm* for above fix. - -Fri Oct 18 15:53:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (devcom): Add tests devcom-some* to test watching just - a single file. - - * root.c (Name_Root): Use isabsolute to test whether a pathname is - absolute instead of checking for the first character being '/'. - (Reported by Antoine P. Brusseau <brusseau@jprc.com>). - - * commit.c (checkaddfile): Free rev only if it is non-NULL (thanks - to cwong@world.std.com (Christopher Wong) for diagnosing this; the - death2-15 test in sanity.sh hits it). - -Thu Oct 17 15:21:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Reenable rdiff tests. Delete rdiff-9 test to reflect - the fact that the change to add a -K option has not been - incorporated. Adjust rdiff-8 test to reflect the fact that the - change to change the default keyword expansion for the first - revision has not been incorporated. - * patch.c (patch_fileproc): Pass the symbolic revision to - RCS_checkout so that Name can be expanded correctly. Reinstates - one of the 30 Sep 96 changes and fixes a bug which the sanity.sh - rdiff test tests for. - - Reinstate change from 30 Sep 96: - * patch.c (patch): CLIENT_SUPPORT: send '-f' if NOT force_tag_match - - * client.c (process_prune_candidates): Do not ignore errors from - unlink_file_dir. - - * filesubr.c (deep_remove_dir): If rmdir returns an error other - than ENOTEMPTY or EEXIST, return -1 not 0. Add workaround for AIX - header bug. - -Tue Apr 30 08:21:27 1996 Mike Sutton <mike_sutton@dayton.saic.com> - - * checkout.c, history.c: added logging/reporting of cvs export - command - -Wed Oct 16 10:16:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Remove tests 4, 4.5, and 4.75; this functionality is - already tested by 45, 45.5 and other tests. - (ignore): New tests ignore-192, ignore-193, ignore-194, and - ignore-195 test output from "cvs release". - (modules2): New tests modules2-6, modules2-7, and modules2-8 test - ability of cvs release to handle multiple arguments. Since it - currently doesn't, the tests are kludged. - - * server.c, cvs.h (cvs_flushout): New function. - * recurse.c (do_file_proc): Call it. - * server.c (cvs_outerr): Call fflush (stdout) in non-server case. - * main.c (main): Don't call setvbuf. The code was incorrectly - checking for "patch" (it really is "rdiff"); the concern about - slowing down large amounts of output is not specific to rdiff - (it applies to "log" for example); and the above changes should - meet the need. - -Tue Oct 15 10:22:10 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - This is intended to facilitate some future cleanups to the - locking, but by itself it is a simple, conversative rearrangement: - * tag.c (locked_dir, locked_list): Move from here... - * lock.c: ...to here. - * lock.c (Lock_Cleanup): If locked_dir is set clean it up too. - * tag.c (tag_unlockdir): Removed; with the above change - Lock_Cleanup suffices. - * tag.c (tag_lockdir): Move from here... - * lock.c (lock_dir_for_write): ...to here. - * tag.c (tag_fileproc), rtag.c (rtag_fileproc): Update callers. - Move comments concerning why we are locking what we are from - tag_lockdir to here. - * tag.c (tag_filesdoneproc), rtag.c (rtag_filesdoneproc): - Update callers. - * lock.c (Writer_Lock): Made static. - * cvs.h: Update declarations. - * server.c (server_notify): Call lock_dir_for_write rather than - calling Writer_Lock ourselves. - - This is intended to facilitate some future cleanups to the - locking, but by itself it is a simple, conversative rearrangement: - * lock.c (Lock_Cleanup): Also dellist (lock_tree_list). - * lock.c, cvs.h (lock_tree_cleanup): Removed; with the above change - Lock_Cleanup suffices. - * commit.c, edit.c, watch.c: Change callers. - -Sat Oct 12 21:41:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (deep): Add comment about whether the deep-4b behavior - is considered desirable. - -Sat Oct 12 20:36:36 1996 Ian Lance Taylor <ian@cygnus.com> - - * client.c (client_send_expansions): Add build_dirs parameter. - Change all callers. - (send_dirent_proc): Get build_dirs from callerdat; if it is - zero, don't send a nonexistent directory to the server. - (send_files): Add build_dirs parameter. Change all callers. - * client.h (send_files): Update prototype. - (send_files_contents): Remove prototype for nonexistent function. - (client_send_expansions): Update prototype. - * sanity.sh (deep): Add deep-4b test for above patch. - -Fri Oct 11 14:07:12 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - gcc -Wall lint: - * logmsg.c (title_proc): Remove unused variables title and comma. - - * sanity.sh (modules2): Don't be picky about whether we are - checking in 1.3 or 1.2 of modules; it depends on whether we are - running all the tests or just some. - -Thu Oct 10 14:52:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c, server.h (server_dir): New variable. - (output_dir): If it is set, send it before the directory name. - * modules.c (do_module): Set it, in the case of & modules, and - restore it when done. - * sanity.sh (modules): Don't clean up first-dir before starting; - tests now clean up for themselves at the end. - (modules2): New tests, for above fix. - -Wed Oct 9 15:52:34 1996 Jim Blandy <jimb@totoro.cyclic.com> - - * sanity.sh: Barf immediately if run as root. - - * rcs.c (RCS_getrevtime): When giving a date to get_date, use the full - year, not the year - 1900, so that dates after 1999 are parsed - correctly. (Change thanks to Paul Eggert.) - -Wed Oct 9 10:59:11 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - Clean up gcc -Wmissing-prototypes lint: - * cvs.h (admin, add, checkout, commit, diff, history, import, - cvslog, login, patch, release, cvsremove, rtag, status, tag): - Declare. - * server.c, main.c: Don't declare them here. Don't declare update - either (which is already declared in cvs.h). - * tag.c, cvs.h, main.c, server.c: Rename tag to cvstag to avoid - name conflicts. - * client.c (init_sockaddr, auth_server_port_number), entries.c - (Entnode_Create, Entnode_Destroy), hash.c (nodetypestring), - login.c (construct_cvspass_filename), server.c - (supported_response), wrapper.c (wrap_matching_entry): Make static; - prototype. - * hash.c (printlist): Prototype. - * myndbm.c (mydbm_load_file): Change declaration to prototype. - -Tue Oct 8 22:35:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (log2): Re-add these tests; they were deleted for 1.9 - (because they were thought to be destabilizing and/or due to - confusion/accident), but they can be put back now. - - * sanity.sh (death2): In tests death2-diff-{2,4,6,8,10}, allow "-" - or "%" in temp file names. The system (tmpnam or whatever) - generates these names so they vary from system to system. - -Tue Oct 8 12:37:09 1996 Ian Lance Taylor <ian@cygnus.com> - - * options.h.in (HAD_RCS4): Remove; no longer used. - -Sun Oct 6 15:58:11 1996 Noel Cragg <noel@gargle.rain.org> - - * The following changes address problem #56 in the GNATS database - on harvey.cyclic.com: - - * logmsg.c (str_list_format): new global -- contains the format - for items to be placed in str_list. - (Update_Logfile): move code that creates the "title" string... - (logfile_write): ...to here. Pull apart the filter program and - look for a format string, extracting it if there is one. - (title_proc): write a given filename/value based on the format - string. - - * commit.c (classify_file_internal): new routine, old code (needed - to use the code in more than one place). Determines the status - and version information about a file. - (check_fileproc): use classify_file_internal. Fill in the rev_old - field for the struct logfile_info. - (commit_fileproc): Fill in the rev_new field. - - * cvs.h (struct logfile_info): add two new fields -- rev_old and - rev_new -- that keep track of revision numbers across commits. - -Fri Sep 27 15:21:47 1996 Peter Wemm <peter@spinner.dialix.com> - - * logmsg.c (do_editor): Do not use editinfo if running on the client. - -Fri Oct 4 15:11:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (server_cleanup): Temporarily clear noexec when calling - unlink_file_dir. This is so we clean up the temp directory even - when the -n global option is specified. - -Wed Oct 2 10:47:33 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * client.c (send_repository): initialize some variables before - first usage - -Tue Oct 1 13:01:24 1996 Jim Blandy <jimb@floss.cyclic.com> - - Revert some of Greg's changes; they're welcome later, but we're - trying to keep CVS stable for pre-release testing at the moment. - * checkin.c, commit.c, cvs.h, diff.c, import.c, main.c, no_diff.c, - options.h.in, patch.c, rcs.c, rcs.h, rcscmds.c, sanity.sh, update.c: - Revert changes of Sep 29 and 30. - -Tue Oct 1 13:17:31 1996 Ian Lance Taylor <ian@cygnus.com> - - Make sure the server temporary directory is removed even if - Max-dotdot is used. - * server.c (orig_server_temp_dir): New static variable. - (serve_max_dotdot): Don't free server_temp_dir if it is the same - as orig_server_temp_dir. - (do_cvs_command): Use orig_server_temp_dir in error message. - (server_cleanup): Remove orig_server_temp_dir. - (server): Set orig_server_temp_dir. Remove incorrect indentation - of error message. - - * import.c (update_rcs_file): Restore new argument to - RCS_checkout, removed in last patch. - -Tue Oct 1 00:32:55 1996 Jim Blandy <jimb@floss.cyclic.com> - - * import.c: Revert Greg Woods' changes of Sep 30. We may want - them later, but not before 1.9. - -Mon Sep 30 23:31:01 1996 Jim Blandy <jimb@floss.cyclic.com> - - * log.c (log_fileproc): Now that we might actually find a "desc" - node in rcsfile->other, thanks to Ian's change below, we had - better deal correctly if we find a null pointer in it. - -Mon Sep 30 13:55:03 1996 Greg A. Woods <woods@most.weird.com> - - * main.c (main): don't set need_to_create_root for "cvs init" - either, just in case it's run from within a valid working - directory. - - * sanity.sh (testcvs): oops, forgot to comment out test version I - was using... - - * diff.c (diff_fileproc): use Diffbin instead of DIFF (3). - * patch.c (patch_fileproc): use Diffbin instead of DIFF. - * commit.c (check_fileproc): use Grepbin instead of GREP. - * rcscmds.c (RCS_merge): use Grepbin instead of GREP. - * update.c (patch_file): use Diffbin instead of DIFF. - (update_fileproc): use Grepbin instead of GREP. - * cvs.h (Diffbin): new declaration. - (Grepbin): new declaration. - (DIFFBIN_ENV): new manifest to name DIFFBIN environ var. - (GREPBIN_ENV): new manifest to name GREPBIN environ var. - * option.h.in (DIFFBIN_DFLT): renamed from DIFF. - (GREPBIN_DFLT): renamed from GREP. - * main.c (main): new variables diffbin_update_env and - grepbin_update_inv, ala rcsbin_update_env. - (main): new options -D diffbin and -g grepbin - (usg): describe new options -D diffbin and -g grepbin. - (Diffbin): new global variable for DIFF path. - (Grepfbin): new global variable for GREP path. - - * options.h.in (RCSBIN_DFLT): mention this needs to be set if - your PATH isn't set properly by rshd. - - * sanity.sh (rdiff): re-do Jim's change, but with the original - keywords I had intended (should be a bit more like real life), and - Jim's better RCS date and user matching form. - [I guess that's what I get for checking things in at 3am! ;-)] - -Mon Sep 30 17:00:20 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_reparsercsfile): Store desc field value in main RCS - node data, not in version specific data. - * sanity.sh: Enable log2 test (for local CVS only). - -Mon Sep 30 13:01:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (log2): New test, tests cvs add -m. Not yet enabled - in "tests" because CVS currently flunks this test. - - * sanity.sh (rdiff, basic2): Allow "cvs server" as well as "cvs - checkout" and friends in messages. In testing output of cvs - status, don't require a tab which isn't there for remote. Skip - test rdiff-9 for remote. In test basic2-64, add missing slash in - the pattern which gets used for remote. - - * sanity.sh (rdiff): Fix strings we were matching against which - got keyword-expanded in checking in sanity.sh. - -Mon Sep 30 03:21:37 1996 Greg A. Woods <woods@most.weird.com> - - * sanity.sh: change all regexpr literal '.' to '\.' - (basic2): why are tests 34 & 42 commented out (because - of 'diff -u'?)? - add tests 56[abc], 57a, and 58a to test import to the main - branch (i.e. branch '1'). - (rdiff): new test section for rdiff -K, etc. - (dotest): remove dotest.ex? before running a new test. - (dotest_fail): remove dotest.ex? before running a new test. - (dotest_internal): write expected output to dotest.exp, or if $4 - also used, to dotest.ex1 and dotest.ex2. - (patch): renamed this test to 'serverpatch'. - (dotest_lit): rename dotest.res to dotest.exp ala dotest(). - remove dotest.ex? before running a new test. - (DOTSTAR): mention the bug exists up to 1.12 - (ENDANCHOR): mention the bug exists up to 1.12 - (dotest_all_in_one): new function for debugging. - (dotest_line_by_line): new function for debugging. - (dotest_internal_debug): new function for debugging. - (dotest_internal): stop emulating the ancient tests and don't spew - the dotest.tmp contents onto $LOGFILE -- it's just too much - meaningless noise. Only do this if the test fails. Many tests - don't use dotest() yet, so this isn't quite so helpful as it might - otherwise be. - (TODO): mention CVS/* files, especially CVS/Root. - - * main.c (main): add a commented out piece of code to suggest that - there should be a function lookup_command_attribute() that could - tell us various things about internal commands, such as whether - they use CVS/Root, or if they're repository-only, or if they need - a working directory, etc.... - (main): don't set need_to_create_root if command doesn't use a - local working directory. - - * patch.c (patch): CLIENT_SUPPORT: send '-f' if NOT force_tag_match - - * error.c (fperror): protect declaration for un-defined __STDC__ - - * import.c (import): permit imports to a branch with zero dots, - i.e. the trunk. - (update_rcs_file): don't detect conflicts if importing to the - trunk. - (import): add hint that we should allow a module name, instead of - just a pathname relative to $CVSROOT. - (add_rcs_file): if importing to trunk, do it with ci(1). - - * import.c: XXX the following are all #if 0'ed out until a full - implementation can be designed.... - (cbranch): new variable to support conflict detection on another - branch set by -c. - (import): truncate -b and -c optarg if to fit in static storage. - (import_usage): describe -c - - * rcscmds.c (RCS_checkout): add new argument 'rcsver'. If rcsver - is set, turn on 'keywords' to force call to RCS_exec_checkout. - * rcs.c (RCS_exec_checkout): add new argument 'rcsver'. Pass - 'rcsver' to "co" with run_arg(). - * cvs.h: (RCS_checkout): add new argument 'rcsver' to prototype. - (RCS_exec_checkout): add new argument 'rcsver' to prototype. - * commit.c (remove_file): supply new argument to RCS_checkout. - * checkin.c (Checkin): supply new argument to RCS_checkout. - * diff.c (diff_fileproc): supply new argument to RCS_checkout. - (diff_file_nodiff): supply new argument to RCS_checkout. - * no_diff.c (No_Difference): supply new argument to RCS_checkout. - * update.c (checkout_file): supply new argument to RCS_checkout. - (patch_file): supply new argument to RCS_checkout. - (join_file): supply new argument to RCS_checkout. - - * patch.c: (o_options): new variable for -K - (rcsver): new variable for -V. - (patch): add -K flag which sets o_options, change -V to set - rcsver, send o_options and rcsver if in client mode. - (patch_fileproc): use RCS_checkout instead of RCS_fast_checkout in - order to ensure $Name is expanded, use o_options if set, or - options if set, or by default "-ko" when getting "old" file. - -Sun Sep 29 16:43:28 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcscmds.c: Replace comment at top of file concerning RCS library - with a reworded version based on discussion between me, Ian, Paul - Eggert, and JimB. - -Sun Sep 29 13:09:45 1996 Noel Cragg <noel@kiva.rain.org> - - * main.c (main): don't create/update CVS/Root when doing the "cvs - login" command. Consider: if the user executes "cvs login" with - the working directory inside an already checked out module, we'd - incorrectly change the CVS/Root file to reflect the CVSROOT of the - "cvs login" command. - - * login.c (login): if we're re-logging into a server for which a - .cvspass entry already exists, copy the temporary file to its home - location rather than renaming. Renaming doesn't work between - filesystems. After copying, unlink the temporary file. - -Fri Sep 27 05:24:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * diff.c: Add comment about --brief option. - - * README-rm-add: Removed; the information which was here is now in - cvs.texinfo. - * Makefile.in (DISTFILES): Remove README-rm-add. - -Wed Sep 25 10:00:00 1996 Larry Jones <larry.jones@sdrc.com> - - * Makefile.in (cvsbug): Add dependency on version.c. - -Wed Sep 25 09:01:48 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * filesubr.c (get_homedir), update.c (update): Reindent. - -Wed Sep 25 04:44:54 1996 Jim Blandy <jimb@totoro.cyclic.com> - - * version.c (version_string): Bump to 1.8.86. - -Wed Sep 25 05:17:50 1996 Jim Blandy <jimb@floss.cyclic.com> - - * update.c (update): Don't neglect to pass the -kmumble options - to the server. - * sanity.sh (binfiles-sticky): New tests for above. - - * cvsrc.c (read_cvsrc): Deal correctly with lines that specify a - command, but no options; don't corrupt argv. - - * sanity.sh: When testing rsh, use the program specified by - the CVS_RSH environment variable, if it's set. Move test to top - of file, so it runs before all other tests (it's really a - meta-test). - - * filesubr.c (get_homedir): Use getpwuid to find the home - directory, if the HOME environment variable isn't set. - * ignore.c (ign_add_file): Call get_homedir to find the user's - home directory; this is more portable than calling getpwuid. - -Tue Sep 24 09:08:17 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * log.c (log_tree): When walking through branches, follow the - ->prev field rather than following ->next which insures that the - loop only executes once and we only see the last branch. - * sanity.sh (multibranch): Test "cvs log" too; tests for above fix. - -Mon Sep 23 09:55:22 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * options.h.in: Fixed some typos in the comments and reindented - them. - -Sat Sep 21 02:33:26 1996 Jim Blandy <jimb@totoro.cyclic.com> - - * sanity.sh: If we're testing remote CVS, make sure rsh itself is - working before running any tests. It's confusing when basica-1 - fails just because you don't have the local host in your .rhosts - file. - - * version.c (version_string): Bump to 1.8.85. - -Thu Sep 19 09:15:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * options.h.in: Define SERVER_FLOWCONTROL, SERVER_HI_WATER, - SERVER_LO_WATER. Several large sites (FreeBSD, Cygnus) have been - pounding on this code without problems, and it doesn't seem to - have any significant downsides. - -Tue Sep 17 01:13:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * status.c (status_fileproc): Instead of a default case, set sstat - before the switch. This way gcc -Wall can detect a missed case. - Add explicit T_TITLE case. - -Tue Sep 17 00:09:44 1996 Assar Westerlund <assar@pdc.kth.se> - - * login.c (login): Print usage if argc < 0. - -Tue Sep 17 00:09:44 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * lock.c: In comment, mention one more function of readlocks - (fileattr not updated atomically). Note similarity between - solutions #2 and #5. - - * checkout.c (safe_location): Do not reject a location merely - because it textually starts with hardpath; insist that it be - hardpath or a subdirectory thereof. - -Mon Sep 16 11:46:36 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (server_cleanup): Add comment about ignoring errors - from unlink_file_dir. - -Mon Sep 16 10:31:48 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * main.c: Add support for -T <tmpdir> command line option. This - is needed for servers started via inetd. - (usg): Added line for -T. Improved -z documentation. - (main): Read default for tmpdir from the environment. Test for 'T' - in getopt loop. Use '/tmp' as ultimative fallback. Update - environment if possible. - - * cvs.h (TMPDIR_ENV): Added for -T <tmpdir> command line option. - - * options.h.in: Add TMPDIR_DFLT - - * import.c (update_rcs_file): Use global variable Tmpdir instead - of reading the environment. - - * server.c (server_cleanup): Use global variable Tmpdir instead of - reading the environment. Also, replace system("rm -rf") with - unlink_file_dir. - (server): Use global variable Tmpdir instead of reading the - environment. - -Thu Sep 12 1996 Jim Kingdon <kingdon@cyclic.com> - - * main.c (main): If ARGV0_NOT_PROGRAM_NAME, then just set - program_name to "cvs" rather than argv[0]. - -Thu Sep 12 12:06:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (update_entries): If we can't write the file, don't - make it a fatal error. - -Wed Sep 11 12:46:23 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (start_server): Move START_SERVER_RETURNS_SOCKET code - so that it is only run for server_method. It is wrong for - pserver_method (in which connect_to_pserver sets server_sock). - - * login.c (construct_cvspass_filename): If NO_SLASH_AFTER_HOME, - don't put a '/' between $HOME and .cvspass. Reindent function. - * build_src.com: Add zlib.c, login.c, and scramble.c. - - * rcs.c (RCS_deltas): When looking for our branch in ->branches, - check the branch number. - * sanity.sh (multibranch): New tests test for above fix. - - * commit.c (precommit_list_proc): Fix typo in last change - (->status to ->type). - -Tue Sep 10 23:05:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in (DISTFILES): Add build_src.com. - * build_src.com: Add buffer.c, buffer.obj, and zlib.olb. - -Tue Sep 10 20:35:23 1996 Juergen Renz <renz@conware.de> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (precommit_list_proc): Update to reflect Jul 22 change - in which p->data was changed from a Ctype to a struct - logfile_info *. This means that commitinfo scripts again get - passed the file list like they should. - -Tue Sep 10 20:35:23 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (auth_server_port_number): Change name of service from - "cvs" to "cvspserver". The latter is what the manual has always - recommended, and it is also officially registered with IANA. - -Tue Sep 10 11:12:42 1996 Mark A. Solinski <markso@mcs.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (socket_buffer_output): Change ifdef VMS to ifdef - SEND_NEVER_PARTIAL. - (start_server): Change ifdef VMS to ifdef START_SERVER_RETURNS_SOCKET. - -Tue Sep 10 17:15:21 1996 Jim Blandy <jimb@totoro.cyclic.com> - - * client.c (auth_server_port_number): Look up "cvs" in the - services database, and use the value it returns; fall back to - CVS_AUTH_PORT if no entry is present. - (connect_to_pserver): Use the correct port number in any error - messages. - -Tue Sep 10 11:12:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (newb): New test newb-123j0 tests for another "cvs - status" case. - -Sun Sep 8 15:20:37 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_checkout): Clarify handling of options parameter. - - * rcs.c (RCS_checkout): Free buffer allocated by RCS_deltas. - -Sat Sep 7 21:28:27 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (struct cmd): Add comment concerning recognizing unique - abbreviations. - -Fri Sep 6 22:31:52 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_checkout): Fix indentation. - -Fri Sep 6 11:48:08 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_checkout): Replace tag parameter with rev and nametag - parameters. Change all callers. - * rcs.h (RCS_checkout): Update declaration. - - * rcs.c (RCS_getversion): Replace return_both parameter with - simple_tag. Change all callers. - (RCS_gettag): Likewise. - * rcs.h (RCS_getversion, RCS_gettag): Update declarations. - * vers_ts.c (Version_TS): Simplify vn_tag initialization using new - simple_tag rather than old return_both. - * cvs.h (struct vers_ts): Clarify vn_tag comment a bit. - - * main.c (usg): Only mention -x if ENCRYPTION is defined. - (main): Mention ENCRYPTION define in comment for -x. - * client.h (krb_encrypt_buffer_initialize): Only declare if - ENCRYPTION is defined. - * client.c (start_server): Only encrypt if ENCRYPTION is defined. - * server.c (serve_kerberos_encrypt): Only define if ENCRYPTION is - defined. - (requests): Only include Kerberos-encrypt is ENCRYPTION is - defined. - (krb_encrypt_*): Only define if ENCRYPTION is defined. - -Thu Sep 5 17:32:39 1996 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh: When testing remote, use :ext: instead of :server: to - match change made earlier today. - -Thu Sep 5 13:57:47 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (start_tcp_server): Don't allow :kserver: to mean - "direct tcp" (root.c already takes care of this, but I want to - make it clear what is intended, and not intended, here). - (start_server): Handle ext_method (external rsh program) and - server_method (internal rsh client) separately. - * client.c: Take rsh_pid and start_rsh_server out of - RSH_NOT_TRANSPARENT ifdefs. It is useful for things like SSH on NT. - * cvs.h (CVSmethod), root.c (method_names): Add ext_method. - * root.c (parse_cvsroot): Recognize "ext" access method. - If access method is not specified and CVSROOT contains a colon, - use either ext_method or server_method depending on - RSH_NOT_TRANSPARENT. - -Thu Sep 5 00:09:49 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_checkout): Remove flags parameter, which was not - serving any useful purpose. Change all callers. - * rcscmds.c (RCS_exec_checkout): Likewise. - - * rcscmds.c (RCS_exec_checkout): Rename from RCS_checkout. Change - all callers. - * rcs.c (RCS_checkout): Rename from RCS_fast_checkout. Change all - callers. - -Wed Sep 4 14:42:28 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_fast_checkout): If tracing, output a message. If - noexec, and workfile is not NULL, just return immediately. Assert - that sout is RUN_TTY or workfile is NULL, rather than using it as - a conditional. Replace found variable with two variables--gothead - and keywords--reflecting what it actually means. - - * rcs.c (RCS_fast_checkout): Don't handle the case of workfile set - to "". - * rcscmds.c (RCS_checkout): Likewise. - * checkin.c (Checkin): Pass explicit file name, not "", to - RCS_fast_checkout. - * update.c (join_file): Likewise. - * commit.c (remove_file): Pass explicit file name to - RCS_fast_checkout and RCS_checkin. - - * rcs.c (RCS_reparsercsfile): Always continue after seeing - RCSSYMBOLS, even if the value is NULL. Clear the NODELTA flag - after setting delta_pos. - (free_rcsnode_contents): New static function. - (freercsnode): Call free_rcsnode_contents. - (RCS_fast_checkout): If NODELTA is set, reparse the RCS file. - (RCS_settag): New function. Change all callers to old function. - (RCS_deltag, RCS_setbranch): Likewise. - (RCS_lock, RCS_unlock): Likewise. - (RCS_deltas): If NODELTA is set, reparse the RCS file. - * rcs.h (NODELTA): Define. - (RCS_settag, RCS_deltag, RCS_setbranch): Declare. - (RCS_lock, RCS_unlock): Declare. - * rcscmds.c (RCS_exec_settag): Rename from RCS_settag. Don't - check tag against BASE or HEAD (now done in new RCS_settag). - (RCS_exec_deltag): Rename from RCS_deltag. - (RCS_exec_setbranch): Rename from RCS_setbranch. - (RCS_exec_lock): Rename from RCS_lock. - (RCS_exec_unlock): Rename from RCS_unlock. - * cvs.h: Update declarations of renamed functions. - * checkin.c (Checkin): Remove rcscopy variable (no longer needed - because of change in RCS_unlock call). - * commit.c: Include <assert.h>. - (remove_file): Update RCSNode path if the file is renamed. - (unblockrcs): Change rcs parameter to RCSNode. Change all - callers. - (fixbranch): Likewise. - (lock_RCS): Likewise. Don't call RCS_parsercsfile. - (checkaddfile): Update RCSNode path if the file is renamed. After - creating a new file, call RCS_parse. When stubbing a branch, use - the passed in RCSNode if there is one, rather than calling - RCS_Parse. Don't call RCS_Parse again after calling RCS_settag. - Free head and magicrev even if RCS_settag fails. - * import.c (add_rev): Change rcs parameter to RCSNode. Change all - callers. - (add_tag): Likewise. - - * rcs.c (RCS_fast_checkout): Amend last patch: if workfile is - NULL, but sout is not NULL, use sout in error message. - -Wed Sep 4 13:35:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Increment version number to 1.8.8. - - * Version 1.8.7. - -Wed Sep 4 1996 Jim Kingdon <kingdon@cyclic.com> - - * client.c (send_file_names): Look for the name to send in - Entries even if the file doesn't exist; we should send the - name as it appears in Entries in the "rm foo; cvs update FOO" - case. - -Tue Sep 3 20:50:11 1996 William A. Hoffman <hoffman@albirio.crd.ge.com> - - * rcs.c (RCS_fast_checkout): If workfile is NULL, don't try to - include it in error message. - -Mon Aug 26 12:27:38 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * mkmodules.c (mkdir_if_needed): Move from here ... - * filesubr.c, cvs.h (mkdir_if_needed): ... to here. Have it - return a value saying whether the directory was created. - * client.c (call_in_directory), edit.c (edit_fileproc): Call it. - -Fri Aug 23 19:19:44 1996 Ian Lance Taylor <ian@cygnus.com> - - * checkin.c (Checkin): Copy rcs parameter in case it is freed when - finfo->rcs is freed. - -Fri Aug 23 14:55:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * remove.c (remove_fileproc): Revert change of 23 Aug to print - getwd and finfo->file in message. The latter is redundant with - fullname and the former is redundant with fullname and the working - directory when CVS was invoked. The implementation was also - lacking as the getwd call could overflow the buffer. - -Fri Aug 23 18:40:35 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * remove.c (cvsremove): fix remove -f for client/server - -Fri Aug 23 11:28:27 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * wrapper.c, cvs.h: Remove conflictHook field of WrapperEntry, - WRAP_CONFLICT in WrapMergeHas, and 'c' option in wrap_add; they - are never used. - -Fri Aug 23 11:41:46 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * server.c (switch_to_user): use #ifdef SETXID_SUPPORT instead of - #if SETXID_SUPPORT - -Thu Aug 22 14:18:43 1996 Ian Lance Taylor <ian@cygnus.com> - - * checkin.c (Checkin): Remove local variable xfinfo. Reparse the - RCS file after the checkin. Call RCS_fast_checkout rather than - RCS_checkout. - - * cvs.h (RCS_FLAGS_LOCK): Don't define. - (RCS_FLAGS_*): Adjust values to fill in hole left by removal of - RCS_FLAGS_LOCK. - * rcs.c (RCS_fast_checkout): Don't check for RCS_FLAGS_LOCK. - * rcscmds.c (RCS_checkout): Likewise. - * commit.c (commit_fileproc): Remove rcs local variable. If - status is T_MODIFIED, require that finfo->rcs be set, call - Lock_RCS directly, and don't call locate_rcs. If adding to a tag, - require that finfo->rcs be set, and don't call locate_rcs. - (remove_file): Remove rcs local variable. Require that finfo->rcs - be set. Don't call locate_rcs. Don't pass RCS_FLAGS_LOCK to - RCS_checkout; use RCS_lock instead. Call RCS_fast_checkout rather - than RCS_checkout. - (unlockrcs): Use a single rcs parameter rather than two parameters - for file and repository. Change all callers. Don't call - locate_rcs. - (fixbranch): Likewise. - (lockrcsfile): Remove; no more callers. - -Tue Aug 20 10:13:59 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * buffer.c, rcs.c: Don't use inline. It wasn't being used in a - loop or any such place where it would matter for performance, and - it was a (minor) portability hassle. - - * server.c (server): Change "Dummy argument 0" to "cvs server" and - add comment explaining why. - - * rcs.c (linevector_add): Add comment regarding changing \n to \0. - -Tue Aug 20 09:19:19 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * checkout.c (checkout_proc): Call RCS_parse to get the default - options from the RCS file. - - * sanity.sh (binfiles): Add tests 5.5b0 and 5.5b1 for the above fix - -Mon Aug 19 18:13:32 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (linevector_init): Make inline. Set lines_alloced to 0, - not 10. Set vector to NULL. - (linevector_add): Remove assertion that lines_alloced is greater - than zero. Initialize lines_alloced if necessary. - (linevector_copy): Initialize lines_alloced if necessary. - (linevector_free): Only free vector if it is not NULL. - (RCS_deltas): Always call linevector_init and linevector_free on - curlines, headlines, and trunklines. - (RCS_fast_checkout): Remove #if 0 around code that calls - RCS_deltas. - -Fri Aug 16 17:52:54 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (linevector_add): Handle zero length correctly. - (RCS_deltas): In RCS_FETCH case, the data is in headlines, not - curlines. - (RCS_fast_checkout): Update comment about RCS_deltas: the - testsuite now passes. - - * rcs.c (RCS_fully_parse): Use the length of the value, rather - than assuming that there are no embedded zero bytes. - (struct line): Add len field. - (linevector_add): Add len parameter. Change all callers. Use - len, rather than assuming that there are no embedded zero bytes. - Set the len field in new lines. - (RCS_deltas): Use the length of the value, rather than assuming - that there are no embedded zero bytes. Use the line length when - outputting it and when copying it. - (RCS_fast_checkout): Update comment about RCS_deltas to remove - note about supporting zero bytes correctly. - -Thu Aug 15 23:38:48 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c, import.c: Revise comments regarding the fact that we - call start_server before do_editor. - -Thu Aug 15 11:30:55 1996 Ian Lance Taylor <ian@cygnus.com> - - * server.c: Include <sys/socket.h> if AUTH_SERVER_SUPPORT. - (pserver_authenticate_connection): Set SO_KEEPALIVE on - STDIN_FILENO. - (kserver_authenticate_connection): Likewise. - -Thu Aug 15 10:26:41 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * server.c (switch_to_user): Fix previous patch to compile it for - both HAVE_KERBEROS and AUTH_SERVER_SUPPORT - -Wed Aug 14 14:02:00 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * server.c (check_password): if available use getspnam instead of - getpwnam when reading system passwords. This allows cvs pserver - to run on systems with shadow passwords. - (switch_to_user): new static function. Contains the extracted - common tail of kserver_authenticate_connection and - pserver_authenticate_connection. If compiled with SETXID_SUPPORT, - honor the setgid bit if it is set. - (check_repository_password): turn into a static function - (check_password): ditto - (pserver_authenticate_connection): little code cleanup - -Wed Aug 14 01:07:10 1996 Greg A. Woods <woods@most.weird.com> - - * history.c (history): apply fix posted by Steven Meyer - <steve@blacksmith.com> to info-cvs to correct handling of '-D' - argument. Message-Id: <9608122335.AA01385@nijel.blacksmith.com> - -Tue Aug 13 13:42:36 1996 Ian Lance Taylor <ian@cygnus.com> - - * log.c (cvslog): Remove comment about calling rlog. - * rcs.c (translate_symtag): Correct typo in comment (l ist -> - list). - * server.c (server_write_entries): Add omitted word (lists) in - comment. - -Tue Aug 13 14:01:49 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * wrapper.c (wrap_rcsoption): fix memory access error - - * rcs.c (RCS_fast_checkout): fix memory access error (triggered - by an empty option string) - -Mon Aug 12 17:45:15 1996 Jim Kingdon (unknown@beezley) - - * buffer.c, zlib.c: If EIO is not defined, try to define it. - -Mon Aug 12 10:33:27 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * import.c (comtable): Add comment concerning applicability with - RCS 5.7. - - * server.c (server): If TMPDIR is not an absolute pathname, give - an error. - -Mon Aug 12 10:34:43 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * main.c: add synonym "ann" for "annotate" again - -Sun Aug 11 17:54:11 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.h (RCS_RLOG): Removed; no longer used. - -Fri Aug 9 20:16:20 1996 Ian Lance Taylor <ian@cygnus.com> - - * server.c (dirswitch): Open the Entries file with mode "a" rather - than "w+". - (server_write_entries): Open the Entries file with mode "a" rather - than "w". - * sanity.sh (modules): Add topfiles module and 155cN tests for - above patch. - -Fri Aug 9 12:11:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (cmd): Add comment regarding synonyms. - -Thu Aug 8 14:40:10 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c: Remove synonyms for "cvs annotate". Synonyms create - user confusion. - -Thu Aug 8 10:24:04 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * main.c: Revert (undocumented) change to rename the cvs history - alias "his" to "hist" - -Wed Aug 7 18:26:25 1996 Ian Lance Taylor <ian@cygnus.com> - - * server.c (cvs_output): Change str parameter to const char *. - Correct loop to print from p, not str. - (cvs_outerr): Likewise. - * cvs.h (cvs_output, cvs_outerr): Update declarations. - - * server.c (receive_partial_file): Read and discard remaining file - data on a write error. - (serve_modified): Discard data while size > 0, not >=. - -Wed Aug 7 15:11:40 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * main.c (cmds): Add some aliases for "annotate". - (usg): Improve usage message text - (cmd_synonyms): New function to print the command synonym list - (main): Add new option --help-synonyms - -Wed Aug 7 00:07:31 1996 Ian Lance Taylor <ian@cygnus.com> - - Keep track of subdirectories in the Entries file. - * cvs.h (enum ent_type): Define. - (struct entnode): Add type field. - (struct stickydirtag): Add subdirs field. - (Subdirs_Known, Subdir_Register, Subdir_Deregister): Declare. - (ignore_files): Update declaration for new parameter. - (FILESDONEPROC): Add entries parameter. - (DIRENTPROC, DIRLEAVEPROC): Likewise. - * entries.c (Entnode_Create): Add type parameter. Change all - callers. - (write_ent_proc): If closure is not NULL, treat it as a pointer to - an int, and set it to 1 if a node is seen which is not ENT_FILE. - (write_entries): If subdirectory information is known, but no - subdirectories were written, write an unadorned D to the file. - (Scratch_Entry): Write an R command to Entries.Log. Don't rewrite - the Entries file. - (Register): Set entfilename. Write an A command rather than an - unadorned entries line. - (fgetentent): Add cmd and sawdir parameters. Change all callers. - If CMD is not NULL, expect and return a single character command. - Handle an initial D by setting the type to ENT_SUBDIR. - (fputentent): Output an initial D for an ENT_SUBDIR entry. - (Entries_Open): Handle removal commands in Entries.Log. Record - whether subdirectory information is known in the list private - data. - (Subdirs_Known): New function. - (subdir_record): New static function. - (Subdir_Register, Subdir_Deregister): New functions. - * find_names.c (add_entries_proc): Skip entries that are not - ENT_FILE. - (add_subdir_proc): New static function. - (register_subdir_proc): New static function. - (Find_Directories): If the Entries file has subdirectory - information, get the directories out of it. Otherwise, call - find_dirs, and add the information to the Entries file. - * recurse.c (struct frame_and_entries): Define. - (do_recursion): Don't call Entries_Close until after processing - dirlist. Pass entries to filesdoneproc. Pass a frame_and_entries - structure to do_dir_proc via walklist. - (do_dir_proc): Expect a frame_and_entries structure in closure, - not a recursion_frame. Pass entries to direntproc and - dirleaveproc. - * ignore.c (ignore_files): Add entries parameter. Change all - callers. If we have subdirectory information, check for - directories in entries. - * add.c (add): If client_active, call Subdir_Register on each new - directory. - (add_directory): Add entries parameter. Change caller. Call - Subdir_Register. - * checkout.c (build_dirs_and_chdir): Call Subdir_Register. - * client.c (call_in_directory): Call Subdir_Register for newly - created directories. Call Subdirs_Known or Find_Directories after - calling Entries_Open. - (process_prune_candidates): Call Subdir_Deregister. - * commit.c (findmaxrev): Skip entries that are not ENT_FILE. - * server.c (dirswitch): Call Subdir_Register. - * update.c (update_dirent_proc): Call Subdir_Register. - (update_dirleave_proc): Call Subdir_Deregister. - * Several files: Change direntproc, dirleaveproc, and - filesdoneproc routines to expect an entries argument. - - * rcs.c (translate_symtag): New static function. - (RCS_gettag): Use translate_symtag rather than RCS_symbols. - (RCS_nodeisbranch, RCS_whatbranch): Likewise. - -Tue Aug 6 15:36:09 1996 Ian Lance Taylor <ian@cygnus.com> - - Finish the conversion of cvs log so that it never invokes rlog. - * log.c (struct log_data): Remove dorlog field. Add nameonly, - header, long_header, statelist, and authorlist fields. - (log_usage): Remove rlog-options. Add -R, -h, -t, -b, -s, -w. - (cvslog): Don't clear opterr. Handle -h, -R, -s, -t, -w. If an - unrecognized option is seen, call usage. - (log_parse_list): New static function. - (log_fileproc): Remove code that called rlog. Check nameonly, - header, and long_header fields in log_data. - (log_version_requested): Check statelist and authorlist. - - * log.c (struct datelist): Define. - (struct log_data): Add datelist and singledatelist fields. - (log_usage): Add -d. - (cvslog): Handle -d. - (log_parse_date): New static function. - (log_fileproc): Do special single date handling. - (log_version_requested): Check datelist and singledatelist. - (log_fix_singledate): New static function. - -Mon Aug 5 23:48:16 1996 Ian Lance Taylor <ian@cygnus.com> - - * log.c (struct option_revlist): Define. - (struct revlist): Define. - (struct log_data): Add default_branch and revlist fields. - (struct log_data_and_rcs): Define. - (log_usage): Add -N and -r. - (cvslog): Handle -N and -r. - (log_parse_revlist): New static function. - (log_fileproc): Call log_expand_revlist and log_free_revlist. - Pass log_data_and_rcs structure to log_count_print via walklist. - (log_expand_revlist, log_free_revlist): New static functions. - (log_version_requested): New static function. - (log_count_print): New static function. - (log_tree): Add log_data and revlist parameter. Change all - callers. - (log_abranch): Likewise. - (log_version): Likewise. Call log_version_requested. - (version_compare): New static function. - * sanity.sh (log): New tests for -r, -b, and -N options to log. - -Sun Aug 4 11:19:30 1996 Ian Lance Taylor <ian@cygnus.com> - - Handle simple cases of cvs log without invoking rlog. - * log.c (struct log_data): Define. - (cvslog): Use getopt to parse options. Set up a log_data - structure, and pass it to start_recursion. - (log_fileproc): Get arguments form callerdat rather than static - variables. In simple cases, print the log information directly, - rather than invoking rlog. - (log_symbol, log_count, log_tree): New static functions. - (log_abranch, log_version, log_branch): New static functions. - * rcs.h (struct rcsnode): Add other field. - (struct rcsversnode): Add other field. - (RCS_fully_parse): Declare. - * rcs.c (getrcsrev): Move declaration to start of file. - (RCS_reparsercsfile): Add all parameter. Change all callers. - (RCS_fully_parse): New function. - (freercsnode): Free other list. - (rcsvers_delproc): Free other list. - * hash.h (enum ntype): Add RCSFIELD. - * hash.c (nodetypestring): Handle RCSFIELD. - -Sat Aug 3 19:39:54 1996 Ian Lance Taylor <ian@cygnus.com> - - * log.c (cvslog): Correct position of CLIENT_SUPPORT #endif. - -Thu Jul 25 12:06:45 1996 Ian Lance Taylor <ian@cygnus.com> - - * update.c (join_file): If merging a branch, and the branch - revision does not exist, just return without doing anything. - * sanity.sh (join): Add cases file7 and file8 to test above - patch. - - * server.c (cvsencrypt): Rename from encrypt, to avoid conflict - with NetBSD unistd.h. Rename all uses. - - * server.c (krb_encrypt_buffer_output): Fix typo in comment (reply - -> replay). - -Thu Jul 25 10:37:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (krb_encrypt_buffer_output): Fix typo in comment - (krb_recv_auth -> krb_recvauth). - -Wed Jul 24 09:28:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * lock.c (set_lock): Adjust comment regarding why we call stat. - -Wed Jul 24 15:06:08 1996 Ian Lance Taylor <ian@cygnus.com> - - Add encryption support over a Kerberos connection. - * main.c (usg): Mention -x if CLIENT_SUPPORT. - (main): Handle -x. - * client.h (encrypt): Declare. - (krb_encrypt_buffer_initialize): Declare. - * client.c (kblock, sched): New static variables if - HAVE_KERBEROS. - (start_tcp_server): Remove sched local variable. Copy - cred.session into kblock. - (start_server): Turn on encryption if requested. - * server.c (kblock, sched): New static variables if - HAVE_KERBEROS. - (serve_kerberos_encrypt): New static function. - (requests): Add "Kerberos-encrypt" if HAVE_KERBEROS. - (kserver_authenticate_connection): Remove sched local variable. - Copy auth.session into kblock. - (encrypt): New global variable. - (struct krb_encrypt_buffer): Define. - (krb_encrypt_buffer_initialize): New function. - (krb_encrypt_buffer_input): New static function. - (krb_encrypt_buffer_output): New static function. - (krb_encrypt_buffer_flush): New static function. - (krb_encrypt_buffer_block): New static function. - (krb_encrypt_buffer_shutdown): New static function. - -Wed Jul 24 09:28:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * recurse.c (do_recursion): Add comment about calling - Name_Repository in !(which & W_LOCAL) case. - - * expand_path.c (expand_variable): Fix typo (varaible -> variable). - -Tue Jul 23 15:05:01 1996 Ian Lance Taylor <ian@cygnus.com> - - * update.c (update_fileproc): In T_REMOVE_ENTRY case, only call - server_scratch_entry_only if ts_user is NULL. - * sanity.sh (death2): Add death2-20 test for above patch. - - * diff.c (diff_fileproc): If a file is not in the working - directory, check that the tag is present before warning that no - comparison is possible. - * sanity.sh (death2): Add death2-diff-9 and death2-diff-10 tests - for above patch. - -Tue Jul 23 12:05:42 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * tag.c (tag_check_valid): Fix indentation. - - * client.c (handle_e): Flush stdout before writing to stderr. - (handle_m): Flush stderr before writing to stdout. - -Fri Jul 19 16:02:11 1996 Mike Ladwig <mike@twinpeaks.prc.com> - - * client.c: Added NO_CLIENT_GZIP_PROCESS to deal with the MacOS - client where Gzip-stream is supported, but "gzip-file-contents" is - not. - -Fri Jul 19 16:02:11 1996 Mike Ladwig <mike@twinpeaks.prc.com> - - * repos.c: Fixed recent patch which added plain fopen rather than - CVS_FOPEN - -Mon Jul 22 22:25:53 1996 Ian Lance Taylor <ian@cygnus.com> - - * logmsg.c (tag): New static variable. - (setup_tmpfile): Don't print the prefix before calling fmt_proc. - Free tag if it is set. - (find_type): Get type from logfile_info struct. - (fmt_proc): Likewise. Print tag information. Handle all prefix - printing. - (revision): Remove static variable. - (Update_Logfile): Remove xrevision parameter. Change all - callers. - (title_proc): Get type from logfile_info struct. - (logfile_write): Remove revision parameter. Change all callers. - * cvs.h (struct logfile_info): Define. - (Update_Logfile): Update prototype. - * commit.c (find_fileproc): Set logfile_info information. - (check_fileproc): Likewise. - (commit_filesdoneproc): Don't call ParseTag. - (update_delproc): Free logfile_info information. - * add.c (add_directory): Set logfile_info information. - * import.c (import): Likewise. - - * tag.c (tag_check_valid): The special BASE and HEAD tags are - always valid. - * sanity.sh (basica): Add basica-6.3 test for above patch. - -Mon Jul 22 14:41:20 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (merge_file): Pass 0 not NULL to checkout_file (20 Jul - 96 change changed other calls to checkout_file but missed this one). - -Sat Jul 20 00:21:54 1996 Ian Lance Taylor <ian@cygnus.com> - - * update.c (join_file): Check whether the target of the merge is - the same as the working file revision before checking whether the - file was added during the merge. - - * update.c (scratch_file): Remove existing parameters, and add a - single parameter of type struct file_info. Change all callers. - Warn if unlink_file fails. - (checkout_file): Remove resurrecting_out parameter. Add adding - parameter. Change all callers. Remove joining code. - (join_file): Remove resurrecting parameter. Rewrite to handle - joining dead or added revisions. - * classify.c (Classify_File): If there is no user file, and the - RCS file is dead, return T_UPTODATE rather than T_CHECKOUT. - * checkout.c (checkout_proc): Set W_ATTIC if there is a join tag. - * sanity.sh (join): New set of tests for above patches. - (death): Adjust tests 86, 89, 89a, 92.1c, 95 for above patches. - (import): Adjust test 113 for above patches. - -Thu Jul 18 19:24:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * lock.c: Add comment explaining what locks are for. Also discuss - various changes to locking which get proposed from time to time. - - * sanity.sh (death2): Change a number of test names from death-* - to death2-*. - - * wrapper.c (wrap_setup): Don't look in repository if client_active. - * wrapper.c, cvs.h (wrap_send): New function. - * update.c (update), import.c (import): Call it. - * sanity.sh (binwrap): Do binwrap tests for remote as well as - local; tests for above fixes. - - * wrapper.c: Add a few FIXME comments. - -Thu Jul 18 18:43:50 1996 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh (patch): Fix names of a couple of tests to say patch - rather than death2. - -Thu Jul 18 16:19:21 1996 Bill Bumgarner <bbum@friday.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add), import.c (add_rcs_file): Check for options from - wrappers and use them if specified. - * cvs.h (WrapMergeHas): Add WRAP_RCSOPTION. - * wrapper.c (WrapperEntry): Add rcsOption field. - (wrap_add): Allow a single character argument to an option. - (wrap_add): Handle -k option. - (wrap_add_entry): Handle rcsOption field. - (wrap_name_has): Handle WRAP_RCSOPTION. - * wrapper.c, cvs.h (wrap_rcsoption): New function. - * add.c, import.c, wrapper.c: Minor beautification (mostly - removing trailing spaces). - * sanity.sh (binwrap): New tests test for this feature. - -Wed Jul 17 10:14:20 1996 Ian Lance Taylor <ian@cygnus.com> - - * checkout.c (checkout): Remove extraneous else accidentally - inserted in last checkin. - -Tue Jul 16 11:37:41 1996 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh (import): Use quoting to avoid expansion of RCS ID - strings. - - * sanity.sh (import): Use dotest to examine the output of test - 113, and the actual contents of the file in test 116. - - * update.c (join_file): Always skip rcsmerge if the two revisions - are the same (the old code always did the rcsmerge when two -j - options were specified). - - * checkout.c (history_name): New static variable. - (checkout): Permit both tag and date to be specified. Set - history_name. - (checkout_proc): Use history_name when calling history_write. - * rcs.c (RCS_getversion): If both tag and date are set, use - RCS_whatbranch to get the branch revision number of a symbolic - tag. - (RCS_getdatebranch): If the branch revision itself is early - enough, then use it if the first branch is not early enough. Add - comment for invalid RCS file. Don't bother to check for NULL - before calling xstrdup, since xstrdup checks anyhow. - - * client.h (file_gzip_level): Declare. - * client.c (file_gzip_level): Define. - (start_server): Don't set gzip_level to zero after sending - Gzip-stream command. Set file_gzip_level after sending - gzip-file-contents command. - (send_modified): Use file_gzip_level rather than gzip_level. - * server.c (server_updated): Likewise. - (serve_gzip_contents): Likewise. - - * sanity.sh (patch): New tests. Test remote CVS handling of - unpatchable files. - - * sanity.sh (death2): Accept a '.' in the temporary file name - printed by diff. - - * rcscmds.c (RCS_checkin): Remove noerr parameter. Change all - callers. - * cvs.h (RCS_checkin): Update declaration. - * commit.c (remove_file): Pass RCS_FLAGS_QUIET to RCS_checkin. - - * history.c (history): Cast sizeof to int to use correct type in - error printf string. - (report_hrecs): Cast strlen result to int to use correct type in - printf string. - - * server.c (cvs_flusherr): Correct typo in comment. - - * rcs.c (getrcskey): Hoist three constant strcmp calls out of the - value reading loop. - - * fileattr.c (fileattr_get): Change parameter types from char * to - const char *. - (fileattr_get0, fileattr_modify, fileattr_set): Likewise. - (fileattr_newfile): Likewise. - * fileattr.h (fileattr_get): Update declaration. - (fileattr_get0, fileattr_modify, fileattr_set): Likewise. - (fileattr_newfile): Likewise. - -Thu May 16 11:12:18 1996 Mark P. Immel <immel@radix.net> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.h, client.c, checkout.c (client_send_expansions): - Pass an additional parameter indicating where the checkout is - to occur, to avoid passing the wrong information to send_files(). - * sanity.sh (basicb): New test basicb-cod-1 tests for above fix. - -Mon Jul 15 18:26:56 1996 Ian Lance Taylor <ian@cygnus.com> - - * recurse.c (do_recursion): Require a repository before calling - Find_Names. - * repos.c (Name_Repository): Remove sanity checks which spend time - examining the filesystem. - -Mon Jul 15 1996 Jim Kingdon <kingdon@cyclic.com> - - * client.c (send_file_names): Send file names as they appear - in CVS/Entries, rather than as specified (in cases where they - might differ in case). - (send_fileproc): Use file name from CVS/Entries (vers->entdata->user) - rather than file name as specified (finfo->file) when available. - -Sun Jul 14 15:39:44 1996 Mark Eichin <eichin@cygnus.com> - and Ian Lance Taylor <ian@cygnus.com> - - Improve diff -N handling of nonexistent tags and removed files. - * diff.c (enum diff_file): New definition for whole file, moving - unnamed enum out of diff_fileproc, renaming DIFF_NEITHER to - DIFF_DIFFERENT, and adding DIFF_SAME. - (diff): Look through the repository even if only one revision is - given. - (diff_fileproc): Change empty_file to be enum diff_file. If there - is no user revision, but there is a repository file, treat it as a - removed file. Pass empty_file to diff_file_nodiff, and set it - from the return value. - (diff_file_nodiff): Change return type to enum diff_file. Replace - just_set_rev parameter with enum diff_file empty_file parameter. - Change handling of a missing tag to return an enum diff_file value - if empty_files is set, rather than reporting an error. Free tmp - if xcmp returns 0. - * sanity.sh (death2): Add tests for above patches. - -Sat Jul 13 19:11:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (annotate): In sending options to server, reverse sense of - test so that we send -f iff -f was specified, rather than iff -f was - not specified. - -Fri Jul 12 20:23:54 1996 Greg A. Woods <woods@most.weird.com> - - * zlib.c (compress_buffer_input): add a couple of casts for - uses of z_stream's next_in and next_out - -Fri Jul 12 18:55:26 1996 Ian Lance Taylor <ian@cygnus.com> - - * zlib.c: New file. - * client.c (log_buffer_block): Call set_block and set_nonblock, - rather than lb->buf->block. - (log_buffer_shutdown): New static function. - (get_responses_and_close): Call buf_shutdown on to_server and - from_server. - (start_server): If "Gzip-stream" is supported, use it rather than - "gzip-file-contents". - * server.c (print_error): Call buf_flush rather than - buf_send_output. - (print_pending_error, serve_valid_responses): Likewise. - (serve_expand_modules, serve_valid_requests): Likewise. - (do_cvs_command): Call buf_flush rather than buf_send_output - before the fork, and in the parent after the child has completed. - In the child, set buf_to_net and buf_from_net to NULL. - (serve_gzip_stream): New static function. - (requests): Add "Gzip-stream". - (server_cleanup): Don't do anything with buf_to_net if it is - NULL. Call buf_flush rather than buf_send_output. Call - buf_shutdown on buf_to_net and buf_from_net. Call error for an - malloc failure rather than buf_output to buf_to_net. - * buffer.h (struct buffer): Add shutdown field. - (buf_initialize): Update declaration for new shutdown parameter. - (compress_buffer_initialize): Declare. - (buf_shutdown): Declare. - * buffer.c (buf_initialize): Add shutdown parameter. Change all - callers. - (buf_shutdown): New function. - * Makefile.in (SOURCES): Add zlib.c - (OBJECTS): Add zlib.o. - ($(PROGS)): Depend upon ../zlib/libz.a. - (cvs): Link against ../zlib/libz.a. - (zlib.o): New target. - -Fri Jul 12 1996 Jim Kingdon <kingdon@cyclic.com> - - * client.c (log_buffer_input, log_buffer_output): Use size_t - to avoid Visual C++ signed/unsigned warnings. - -Thu Jul 11 22:01:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (handle_f): Reindent. - - * client.c (mode_to_string, handle_m, handle_e, - auth_server_port_number, get_responses_and_close), server.c - (pserver_authenticate_connection, serve_modified, - serve_enable_unchanged, wait_sig, server_cleanup): Reindent. - * server.c: Remove #if 0'd block of code above - check_repository_password; it was yanked out of some unknown - context and didn't seem to be very useful. - -Thu Jul 11 20:10:21 1996 Ian Lance Taylor <ian@cygnus.com> - - * server.c (do_cvs_command): Pass new special parameter to - buf_copy_counted. If it gets set to -1, send an 'F' response if - the client supports it, and call cvs_flusherr. - (cvs_flusherr): New function. - * cvs.h (cvs_flusherr): Declare. - * client.c (handle_f): New static function. - (responses): Add "F". - * buffer.c (buf_send_special_count): New function. - (buf_copy_counted): Add special parameter. Handle negative counts - specially. - * buffer.h (buf_send_sepcial_count): Declare. - (buf_copy_counted): Update declaration. - * lock.c (lock_wait, lock_obtained): Call cvs_flusherr. - - Change the client to use the buffer data structure. - * client.c: Include "buffer.h". - (to_server): Change to be struct buffer *. - (to_server_fp): New static variable. - (from_server): Change to be struct buffer *. - (from_server_fp): New static variable. - (from_server_logfile, to_server_logfile): Remove. - (buf_memory_error): New static function. - (struct log_buffer): Define. - (log_buffer_initialize, log_buffer_input): New static functions. - (log_buffer_output, log_buffer_flush): New static functions. - (log_buffer_block): New static function. - (struct socket_buffer): Define if NO_SOCKET_TO_FD. - (socket_buffer_initialize): New static function if - NO_SOCKET_TO_FD. - (socket_buffer_input, socket_buffer_output): Likewise. - (socket_buffer_flush): Likewise. - (read_line): Rewrite to use buf_read_line. Remove eof_ok - parameter (it was always passed as 0); change all callers. - (send_to_server): Rewrite to use buf_output. - (try_read_from_server): Rewrite to use buf_read_data. - (get_responses_and_close): Use from_server_fp and to_server_fp for - the streams. Check buf_empty_p when checking for dying gasps. - (start_server): Don't set from_server_logfile and - to_server_logfile; instead, call log_buffer_initialize. If - NO_SOCKET_TO_FD and use_socket_style, call - socket_buffer_initialize; otherwise, call - stdio_buffer_initialize. - * buffer.c: Compile if CLIENT_SUPPORT is defined. - (buf_flush): Fix comment to describe return value. - (buf_read_line): Add lenp parameter. Change all callers. Look - for a line terminated by \012 rather than \n. - * buffer.h: Compile if CLIENT_SUPPORT is defined. - (buf_read_line): Update declaration. - - * server.c (server): Initialize buf_to_net, buf_from_net, - saved_output, and saved_outerr before setting error_use_protocol. - (pserver_authenticate_connection): Don't set error_use_protocol. - Errors before the authentication is complete aren't handled - cleanly anyhow. Change error call after authentication to use - printf. - -Thu Jul 11 1996 Jim Kingdon <kingdon@cyclic.com> - - * client.c (start_server): Open logfiles in binary, not text, mode. - -Wed Jul 10 19:24:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (print_pending_error, print_error): Remove comments - about deadlocks; they don't apply here. Add comments saying - that these functions must only be called when it is OK to - send output (which is why the deadlock concern doesn't apply). The - comments remain for server_cleanup and serve_valid_responses, - where they are an example of the "print a message and exit" - behavior which is noted in cvsclient.texi and which also exists - places like kserver_authenticate_connection. - -Wed Jul 10 18:24:46 1996 Ian Lance Taylor <ian@cygnus.com> - - * server.c (print_error): Add comment warning about potential - deadlock. - (print_pending_error, serve_valid_responses): Likewise. - (server_cleanup): Likewise. - (serve_directory): Don't call buf_send_output. - (serve_modified, serve_notify, server, cvs_outerr): Likewise. - (serve_expand_modules): Call buf_send_output. - (serve_valid_requests): Likewise. - -Wed Jul 10 15:51:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): Print a warning for rlog command. - -Wed Jul 10 15:00:55 1996 Ian Lance Taylor <ian@cygnus.com> - - Abstract the buffer data structure away from the underlying - communication medium. - * buffer.h (struct buffer): Remove fd and output fields. Add - input, output, flush, block, and closure fields. - (buf_initialize, buf_nonio_initialize): Declare. - (stdio_buffer_initialize, buf_flush): Declare. - (buf_read_line, buf_read_data): Declare. - * buffer.c: Include <assert.h>. Don't include <fcntl.h>. - (O_NONBLOCK, blocking_error): Don't define. - (buf_initialize, buf_nonio_initialize): New functions. - (buf_send_output): Use output function, rather than write. - (buf_flush): New function. - (set_nonblock, set_block): Use block function, rather than calling - fcntl. - (buf_send_counted): Don't check output. - (buf_input_data): Call input function, rather than read. - (buf_read_line, buf_read_data): New functions. - (buf_copy_lines, buf_copy_counted): Don't check output. - (stdio_buffer_initialize): New function. - (stdio_buffer_input, stdio_buffer_output): New static functions. - (stdio_bufer_flush): New static function. - * server.c: Include "getline.h". - (buf_to_net): Change to be a pointer. Change all uses. - (protocol, saved_output, saved_outerr): Likewise. - (buf_from_net): New static variable. - (no_mem_error, NO_MEM_ERROR, read_line): Remove. - (struct fd_buffer): Define. - (fd_buffer_initialize, fd_buffer_input): New static functions. - (fd_buffer_output, fd_buffer_flush): New static functions. - (fd_buffer_block): New static function. - (serve_directory): Call buf_read_line rather than read_line. - (serve_notify, server): Likewise. - (receive_partial_file): Call buf_read_data rather than fread. - (serve_modified): Call buf_read_line rather than read_line. Call - buf_read_data rather than fread. - (do_cvs_command): Initialize buffers with fd_buffer_initialize. - Change stdoutbuf, stderrbuf, and protocol_inbuf to be pointers. - (server): Initialize buffers using fd_buffer_initialize, - stdio_buffer_initialize, and buf_nonio_initialize. - (check_repository_password): Call getline rather than read_line. - -Wed Jul 10 15:51:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (find_fileproc): Add comments describing a few cases - that we aren't handling. - -Tue Jul 9 04:33:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_deltas): New function, created from guts of old - annotate_fileproc. - (annotate_fileproc): Call RCS_deltas. - (RCS_fast_checkout): Call it (commented out for now; see comment - for reasons). - - * cvs.h, recurse.c (start_recursion): Add callerdat argument. - * cvs.h: Add callerdat argument to recursion processor callbacks. - * recurse.c: add it to struct recursion_frame and pass it to all - the callbacks. - * admin.c, client.c, commit.c, diff.c, edit.c, lock.c, log.c, - patch.c, rcs.c, remove.c, rtag.c, status.c, tag.c, update.c, - watch.c: Update all the functions used as callbacks. Update calls - to start_recursion. - * commit.c (find_filesdoneproc, find_fileproc, find_dirent_proc, - commit), tag.c (val_fileproc, tag_check_valid): Use callerdat - instead of a static variable. - - * recurse.c (do_recursion): Make static and move declaration to here... - * cvs.h: ...from here. - * recurse.c (do_recursion): Replace plethora of arguments with - single struct recursion_frame *. Change callers. - * recurse.c: New structure frame_and_file. Use it and existing - struct recursion_frame structures to pass info to do_file_proc and - do_dir_proc. Remove globals fileproc, filesdoneproc, direntproc, - dirleaveproc, which, flags, aflag, readlock, and dosrcs. - -Tue Jul 9 11:13:29 1996 Ian Lance Taylor <ian@cygnus.com> - - * modules.c (do_module): Call cvs_outerr rather than fprintf. - -Mon Jul 8 1996 Jim Kingdon <kingdon@cyclic.com> - - * rcs.c (RCS_fast_checkout): If -kb is not in use, open the - working file in text, not binary, mode. - -Sun Jul 7 10:36:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcscmds.c (RCS_settag): Add comment regarding moving check for - reserved tag names to RCS_check_tag. - - * rcscmds.c: Add comment regarding librarifying RCS and related - issues. This is a lightly edited version of a message I sent to - the CVS developers and didn't get flamed for, so it would appear - to be relatively uncontroversial. - - * rcs.c (annotate): Remove comment suggesting -r option and - related functionality; it is done. - -Fri Jul 5 17:19:57 1996 Ian Lance Taylor <ian@cygnus.com> - - * client.c (last_entries): Make file static, rather than function - static within call_in_directory. - (get_responses_and_close): If last_entries is not NULL, pass it to - Entries_Close. - - * server.c (server_pause_check): Check for errors when reading - from flowcontrol_pipe. - - * client.c (call_in_directory): If dir_name is ".", call - Create_Admin if there is no CVS directory. - (send_dirent_proc): If there is no CVS subdirectory, pretend that - the directory does not exist (i.e., don't try to send any files in - the directory). - * server.c (dirswitch): If dir is "." in the top level repository, - add "/." after the Repository entry. - * sanity.sh (modules): Add test 155b for above patches. - -Thu Jul 4 15:57:34 1996 Ian Lance Taylor <ian@cygnus.com> - - * server.c (buf_to_net): Move definition near top of file. - (read_line): Call buf_send_output rather than fflush. - (print_error): Output information to buf_to_net buffer rather than - stdout. - (print_pending_error, serve_valid_responses): Likewise. - (server_notify, do_cvs_command, server_co): Likewise. - (expand_proc, serve_expand_modules, server_prog): Likewise. - (serve_valid_requests, server_cleanup, server): Likewise. - (server_notify): Don't call fflush on stdout. - (do_cvs_command): Flush saved_output and saved_outerr to - buf_to_net before fork. Flush buf_to_net before fork. In child, - just initialize memory_error field of saved_output and - saved_outerr. - (server_cleanup): Flush buf_to_net. - (server): Initialize saved_output and saved_outerr. - (cvs_output): Add support for error_use_protocol case. - (cvs_outerr): Likewise. - * error.c (error): In HAVE_VPRINTF case, just call cvs_outerr. - - * buffer.c: New file; buffer support functions taken from - server.c. - * buffer.h: New file; declarations for buffer.c. - * server.c: Move buffer support functions into buffer.c and - buffer.h. Include "buffer.h". - * Makefile.in (SOURCES): Add buffer.c. - (OBJECTS): Add buffer.o. - (HEADERS): Add buffer.h. - -Thu Jul 4 00:12:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Increment version number to 1.8.6. - -Wed Jul 3 22:31:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Version 1.8.5. - -Wed Jul 3 21:51:23 1996 Ian Lance Taylor <ian@cygnus.com> - - * server.c (blocking_error): Define macro. - (buf_send_output, buf_input_data): Use blocking_error rather than - #ifdef EWOULDBLOCK. - -Tue Jul 2 20:38:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add): Change message which said "version 1.2 of foo.c - will be resurrected"; the message was confusing because it made - people think that the old contents of the file would come back - instead of the contents in the working directory. - -Mon Jul 1 01:38:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * find_names.c (find_dirs): Add comment explaining why we bother - with the entries stuff. - -Sat Jun 29 20:23:50 1996 Ian Lance Taylor <ian@cygnus.com> - - * find_names.c (Find_Directories): Add entries parameter, and pass - it to find_dirs. - (find_dirs): Add entries parameter, and skip all files it names. - * cvs.h (Find_Directories): Update declaration. - * recurse.c (start_recursion): Pass NULL to Find_Directories. - (do_recursion): Pass entries to Find_Directories. - - * client.c (send_modified): Add trace output. - - * diff.c (diff_fileproc): Always call diff_file_nodiff. Handle - dead versions correctly. Handle diffs between a specified - revision to a dead file correctly. - (diff_file_nodiff): Add just_set_rev parameter. Change caller. - * patch.c (patch_fileproc): Check for dead versions. - * sanity.sh (death2): Add tests for above patches. - -Fri Jun 28 20:30:48 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - For reference, this takes CVS's text segment from 271136 bytes to - 270352 bytes, a saving of 784. Not as good as I had hoped (oh well, - the source *seems* simpler at least). - * checkin.c (Checkin), commit.c (finaladd, remove_file), update.c - (join_file, checkout_file, patch_file), no_diff.c - (No_Differences), server.c (server_updated), classify.c - (Classify_File), vers_ts.c (Version_TS), diff.c (diff_file_nodiff): - Use a single struct file_info * argument instead of a bunch of - separate arguments for each of its fields. Remove local fullname - emulations. Use fullname in error messages where file had - erroneously been used. - * cvs.h: Update declarations of above functions and move them to - after the struct file_info declaration. - * server.h: Update declarations. - * add.c, admin.c, checkin.c, checkout.c, classify.c, client.c, - commit.c, diff.c, history.c, import.c, update.c, status.c, - remove.c, rtag.c, tag.c: Change callers. - - * diff.c (diff): Remove -q and -Q command options. This somehow - slipped through the cracks of the general removal of -q and -Q - command options on Jul 21 1995. Note that there is no need to - accept and ignore these options in server mode, like there is for - some of the commands, because the client has never sent -q and -Q - command options for "cvs diff". - -Fri Jun 28 16:50:18 1996 Ian Lance Taylor <ian@cygnus.com> - - * add.c (add): Pass force_tag_match as 1 when calling Version_TS. - * sanity.sh (death2): Add test for above patch. Also add - commented out test for adding a file on a nonbranch tag, which CVS - currently, mistakenly, permits. - -Thu Jun 27 23:20:49 1996 Ian Lance Taylor <ian@cygnus.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * diff.c (longopts): New static array. - (diff): Handle long options and new short options in diff 2.7. - Fix arbitrary limit associated with the tmp variable. - * client.c (send_option_string): Parse options as space separated, - rather than requiring all options to be single characters. - * diff.c, options.h.in: Remove CVS_DIFFDATE; the need for it is gone - now that we have --ifdef (the new behavior is the behavior which - was the default, which is that -D specifies a date). - -Wed Jun 26 22:36:29 1996 Ian Lance Taylor <ian@cygnus.com> - - * commit.c (check_fileproc): If there is a tag, permit adding a - file even if the RCS file already exists. - (checkaddfile): If there is a tag, use the file in the regular - repository, rather than the Attic, if it exists. - * sanity.sh (death2): New set of tests for above patch. - -Tue Jun 25 23:34:13 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (checkout_file): Add comments about two cases which - seem fishy. - - * sanity.sh (basic2, death): Add comments encouraging people to - stop making these sections bigger and more complex. I'm not (yet - at least) trying to figure out the ideal size for a section (my - current best estimate is 10-20 tests), but surely these - two sections are pushing the limit, whatever it is. - -Tue Jun 25 19:52:02 1996 Ian Lance Taylor <ian@cygnus.com> - - * update.c (checkout_file): Rewrite handling of dead files when - joining. Avoid space leaks. Avoid unnecessary file - resurrections. - (join_file): Add checks to skip merging a dead revision onto a - dead revision, and to skip merging a common ancestor onto a dead - revision. Move check for non-existent working file after new - checks. - * sanity.sh (death): Use dotest for tests 86 and 95, and add test - death-file2-1, to test above changes. - -Mon Jun 24 11:27:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (merge_file): Replace file, repository, entries, and - update_dir arguments with finfo argument. Use fullname field - instead of locally emulating it. - (update_fileproc): Update caller. - (merge_file): If -kb is in effect, call it a conflict, leave - the two versions in the file and the backup file, and tell the - user to deal with it. The previous behavior was that the merge - would fail and then there was no way to do a checkin even once you - resolved the conflict (short of kludges like moving the file - aside, updating, and then moving it back). - * sanity.sh (binfiles): New tests binfiles-con* test for above - behavior. Adjust remaining tests to reflect changes in revision - numbers. - -Mon Jun 17 15:11:09 1996 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh (import): Remove sleep. Requiring it was a bug, and - it is fixed in the current sources. - -Mon Jun 17 1996 Ian Lance Taylor <ian@cygnus.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (TMPPWD): Set to real name of /tmp directory. - (basic2-64, conflicts-126.5): Use ${TMPPWD}. - -Mon Jun 17 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcscmds.c (RCS_checkout): Remove noerr parameter. Change all - callers. - * rcs.c (RCS_fast_checkout): Likewise. - -Mon Jun 17 1996 Ian Lance Taylor <ian@cygnus.com> - - Cleaner implementation of tag locking code added Jun 13 1996: - * cvs.h (tag_lockdir, tag_unlockdir): Declare. - * rtag.c (locked_dir, locked_list): Remove. - (rtag_fileproc): Don't lock here; just call tag_lockdir. - (rtag_filesdoneproc): Don't unlock here; just call tag_unlockdir. - * tag.c (locked_dir, locked_list): Move farther down in file. - (tag_fileproc): Don't lock here; just call tag_lockdir. - (tag_filesdoneproc): Don't unlock here; just call tag_unlockdir. - (tag_lockdir, tag_unlockdir): New functions. - -Wed Jun 15 07:52:22 1996 Mike Ladwig <mike@twinpeaks.prc.com> - - * client.c (send_modified, update_entries): Fixed bug which didn't - handle binary file transfers in BROKEN_READWRITE_CONVERSION. - -Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (checkout_file): Call server_scratch_entry_only when a - non-pertinent file is found that does not exist. - * sanity.sh (newb): Add test case for above patch. - -Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com> - - * update.c (update_fileproc): Call server_scratch_entry_only when - handling T_REMOVE_ENTRY on the server. - * sanity.sh (conflicts2): Remove special case for remote server - bug fixed by above patch. - -Thu Jun 13 21:16:26 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basica-9): Update to reflect change to "sufficient - access" message. - -Thu Jun 13 20:13:55 1996 Ian Lance Taylor <ian@cygnus.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * recurse.c, cvs.h (start_recursion): Remove wd_is_repos argument; - add comment about meaning of which argument. Use !(which & - W_LOCAL) instead of wd_is_repos. - * admin.c, client.c, commit.c, diff.c, edit.c, lock.c, log.c, - patch.c, rcs.c, remove.c, rtag.c, status.c, tag.c, update.c, - watch.c: Change callers. This is a semantic change in only two - cases: (1) tag_check_valid, where repository was not "", and (2) - the pipeout case in checkout_proc. In both of those cases the - previous setting of wd_is_repos did not reflect whether we - actually were cd'd into the repository. - * recurse.c (start_recursion): Only check for the CVS subdirectory - if which & W_LOCAL. - * sanity.sh (devcom): Add test case fixed by above patch. - -Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com> - - * ignore.c (ignore_files): Skip based on the file name before - calling lstat. - - * client.c (last_register_time): New static variable. - (update_entries): Set last_register_time when calling Register. - (get_responses_and_close): If the current time is the same as - last_register_time, sleep for a section to avoid timestamp races. - -Thu Jun 13 17:24:38 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (supported_request): Reindent. - -Thu Jun 13 1996 Mark H. Wilkinson <mhw@minster.york.ac.uk> - - * options.h.in, mkmodules.c: Corrections to allow compilation of - non-client-server version. - -Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com> - - * tag.c (tag_check_valid_join): New function. - * cvs.h (tag_check_valid_join): Declare. - * checkout.c (join_tags_validated): New static variable. - (checkout_proc): Check validity of join tags. - * update.c (update): Likewise. - - * tag.c (tag_check_valid): Correct sizeof CVSROOTADM_HISTORY to - use CVSROOTADM_VALTAGS. - - * lock.c (Writer_Lock): If we called lock_wait to wait for a lock, - then call lock_obtained when we get it. - (set_lock): Likewise. - (lock_obtained): New static function. - -Thu Jun 13 13:55:38 1996 Ian Lance Taylor <ian@cygnus.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): If we can't read cvs root, don't say "you don't - have sufficient access"; just print the message from errno. It - might be "No such file or directory" or something else for which - "you don't have sufficient access" doesn't make any sense. - -Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com> - - * commit.c (remove_file): Pass noerr as 0 to RCS_checkout. - -Thu Jun 13 12:55:56 1996 Ian Lance Taylor <ian@cygnus.com> - - * patch.c: Initialize rev1_validated and rev2_validated to 0, not 1. - -Thu Jun 13 12:55:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rtag.c (locked_dir): Revise comments regarding locking; the rtag - and tag situations are different (changing from readlocking one - directory at a time to writelocking one directory at a time does - not do everything we might want, but it does fix simultaneous tags - and it doesn't make anything worse). - -Thu Jun 13 1996 Ian Lance Taylor <ian@cygnus.com> - - Prevent simultaneous tag operations from interfering with each - other. - * rtag.c (rtag_proc): Pass rtag_filesdoneproc to start_recursion, - and pass readlock as 0. - (locked_dir, locked_list): New static variables. - (rtag_fileproc): Write lock the repository if it is not already - locked. - (rtag_filesdoneproc): New static function to unlock the - repository. - * tag.c (tag): Pass tag_filesdoneproc to start_recursion, and pass - readlock as 0. - (locked_dir, locked_list): New static variables. - (tag_fileproc): Write lock the repository if it is not already - locked. - (tag_filesdoneproc): New static function. - -Thu Jun 13 11:42:25 1996 Mike Sutton <mws115@llcoolj.dayton.saic.com> - - * sanity.sh: Allow digits in usernames. - -Wed Jun 12 16:23:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (send_modified, update_entries): Reindent and add - comments to BROKEN_READWRITE_CONVERSION code. - -Wed Jun 12 16:23:03 1996 Mike Ladwig <mike@twinpeaks.prc.com> - - * client.c (send_modified, update_entries): Add - BROKEN_READWRITE_CONVERSION code. - -Mon Jun 10 20:03:16 1996 J.T. Conklin <jtc@cygnus.com> - - * rcs.c (RCS_gettag): No longer set p to NULL if rcs is also NULL. - rcs will never be null, thanks to the assertion at top of function. - -Mon Jun 10 16:28:14 1996 Ian Lance Taylor <ian@cygnus.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): Ignore CVS/Root file when doing an import. - -Fri Jun 7 18:20:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * status.c (status_fileproc, tag_list_proc): Use cvs_output rather - than writing to stdout directly. - -Wed Jun 5 13:54:57 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (force_tag_match, tag, date): New static variables. - (annotate_fileproc): Redo the loop to look for the version - specified by tag/date/force_tag_match, and handle branches - correctly. - (annotate_usage): Mention -f, -r, and -D. - (annotate): Handle -f, -r, and -D. - -Tue Jun 4 13:38:17 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (annotate_fileproc): Skip unrelated branch deltas. - -Fri Jun 7 13:04:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): Change INITIALIZE_SOCKET_SUBSYSTEM to - SYSTEM_INITIALIZE and pass it pointers to argc and argv. Rename - CLEANUP_SOCKET_SUBSYSTEM to SYSTEM_CLEANUP. - -Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com> - - * import.c (add_rcs_file): make buf char[] not unsigned char[] - -Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com> - and Jim Kingdon <kingdon@cyclic.com> - - * main.c (main): Add CLEANUP_SOCKET_SUBSYSTEM hook at end. Revise - comments regarding INITIALIZE_SOCKET_SUBSYSTEM. - -Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com> - and Jim Kingdon <kingdon@cyclic.com> - - * main.c (main): Don't mess with signals if DONT_USE_SIGNALS is - defined. - -Thu Jun 6 15:32:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * modules.c (cat_module): Always format for 80 columns rather than - trying to determine how wide the screen is. The code we had for - the latter didn't cover all cases, was a portability headache, and - didn't work client/server. - -Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com> - - * error.c: Don't declare strerror if it is #defined. - -Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com> - and Jim Kingdon <kingdon@cyclic.com> - - * cvs.h: If ENUMS_CAN_BE_TROUBLE, typedef Dtype to int not an enum. - -Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com> - and Jim Kingdon <kingdon@cyclic.com> - - * update.c (update): If DONT_USE_PATCH, don't request patches. - Also call supported_request rather than reimplementing it. - -Wed Jun 05 10:07:29 1996 Mike Ladwig <mike@twinpeaks.prc.com> - - * client.c (read_line): Changed an occurence of '\n' to '\012'. - -Wed Jun 5 17:18:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add_directory): Don't create the directory if noexec. - * sanity.sh (basica): New tests basica-1a10, basica-1a11 test for - above fix. - * sanity.sh (basicb): New tests basicb-2a10, basicb-2a11, - basicb-3a1 test for analogous situation with files rather than - directories. - -Tue Jun 4 13:38:17 1996 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh: When doing a remote check, use :server: in CVSROOT. - -Wed Jun 5 13:32:40 1996 Larry Jones <larry.jones@sdrc.com> - and Jim Kingdon <kingdon@cyclic.com> - - * ignore.c: Set ign_hold to -1 when not holding instead of 0 so - that holding an empty list works correctly. - * sanity.sh (ignore): New tests 190 & 191 for above fix. - -Wed Jun 5 1996 Jim Kingdon <kingdon@cyclic.com> - - Visual C++ lint: - * client.c (update_entries): Copy the size to an unsigned variable - before comparing it with unsigned variables. - (handle_created, handle_update_existing): Prototype. - -Tue Jun 4 10:02:44 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (responses): Add Created and Update-existing responses. - * server.c (server_updated): If they are supported, use them - instead of Updated. - * client.c (struct update_entries_data): Add existp field. - (handle_checked_in, handle_updated, handle_new_entry, - handle_merged, handle_patched): Set it. - (handle_update_existing, handle_created): New functions, - for new responses. - (update_entries): Based on existp, check for - existence/nonexistence of file. - (try_read_from_server): Expand comment. - * server.c, server.h (server_updated): New argument vers. - * checkin.c (Checkin), commit.c (commit_fileproc), update.c - (update_fileproc, merge_file, join_file): Pass it. - * cvs.h: Move include of server.h after Vers_TS declaration. - * sanity.sh (conflicts2): New tests conflicts2-142d* test for - above fix. - - * sanity.sh (ignore): Fix typo in comment. - - * tag.c (tag_check_valid): Add comment clarifying when val-tags - entries are created. - -Mon Jun 3 07:26:35 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Increment version number to 1.8.4. - -Mon Jun 3 02:20:30 1996 Noel Cragg <noel@gargle.rain.org> - - * version.c: version 1.8.3. - -Thu May 30 10:07:24 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (cmds): Fix typo ("bdif" -> "dif") which was accidentally - introduced 24 May 96. - - * main.c (main_cleanup): Add comment stating default case will - never be reached. - -Wed May 29 21:43:43 1996 noel <noel@BOAT_ANCHOR> - - * main.c (main_cleanup): check to see if SIGHUP, SIGINT, SIGQUIT, - SIGPIPE, and SIGTERM are defined before using them. Also add a - default case to print out those errors numerically which are not - found. - -Wed May 29 18:43:45 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * expand_path.c (expand_path): Document LINE == 0 and allocation - of return value. - * modules.c (do_module): Pass 0, not -1, to indicate line number - not known. Free value returned from expand_path. Deal with NULL - return from expand_path. - -Wed May 29 15:56:47 1996 Greg A. Woods <woods@most.weird.com> - - * modules.c (do_module): call expand_path() on the program name - specfied by one of '-o', '-t', or '-e' in the modules file before - passing it to run_setup(). This makes it possible to use $CVSROOT - (or indeed ~user or any other user-specified variable) to specify - pathnames for programs not installed in the normal execution path. - -Sun May 26 21:57:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (start_server): Don't include %s in error message; - there is no argument to go with it. Do include "internal error" - in error message since that might not be clear to the user otherwise. - -Sun May 26 11:58:13 1996 Greg A. Woods <woods@most.weird.com> - - * root.c (set_local_cvsroot): enforce a wee bit of portability - (parse_cvsroot): same.... - (DEBUG main): same, plus style guidelines - (DEBUG error): deleted -- not necessary here (use fprintf instead) - - * mkmodules.c (modules_contents): updated notes about what must be - done if you change any of the options for a module. - (loginfo_contents): fixed grammar, re-pargraphed, and added 'echo - %s;' to the example. - (editinfo_contents): minor grammar fix. - -Sun May 26 17:51:18 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * vers_ts.c (Version_TS): Remove case where we get options from - sdtp->options. Whatever case that was intended to handle is - probably lost in the mists of time, but sdtp->options isn't set - anywhere, and I think that has been true for a long time. - * cvs.h (struct stickydirtag): remove options field. - * entries.c (freesdt): Don't free ->options. - * sanity.sh (binfiles): New tests binfiles-13a* test for above fix. - - * tag.c (check_fileproc): Use fullname not file in error message. - Say "locally modified" not "up-to-date"; the file need not match - the head revision it only need match some revision. - -Sun May 26 16:57:02 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * tag.c: added support for new option -c to make sure all tagged - files are up-to-date - (tag): check for option and set check_uptodate - (check_fileproc): check status of file if check_uptodate is set - -Sat May 25 15:22:26 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): Revert change to look for a -H command option; - command option parsing should be up to each subcommand and the -H - global option works fine. - -Mon May 23 1996 Ian Lance Taylor <ian@cygnus.com> - - * client.c (process_prune_candidates): Set prune_candidates to - NULL at the end of the function. - -Mon May 23 1996 Ian Lance Taylor <ian@cygnus.com> - - * checkout.c (checkout): In code to handle multiple arguments, - pass preload_update_dir, not where, to Create_Admin. - (checkout_proc): Pass preload_update_dir, not where, to - Create_Admin. - -Thu May 23 19:14:35 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (server_set_sticky): Assert that update_dir != NULL. - * sanity.sh (basicb): New test; tests for Ian's fix to checkout.c - above. - -Thu May 23 1996 Ian Lance Taylor <ian@cygnus.com> - - * patch.c (patch_fileproc): Don't ignore a file just because it is - in the Attic directory. - -Thu May 23 10:40:24 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (death): New tests death-{72a,76a0,76a1} test for bug - fixed by Ian's patch_fileproc change above. - - * sanity.sh (death): Remove "temporary hack" in test 89. - - * rcs.c (RCS_fast_checkout): If error closing file, and workfile - is NULL, use sout in error message instead of workfile. - -Thu May 23 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_fast_checkout): Do a fast checkout in the case where - workfile is NULL and sout is a file name. - -Wed May 22 19:06:23 1996 Mark Immel <immel@centerline.com> - - * update.c (checkout_file): New arg resurrecting_out, to provide - resurrecting flag to caller. - (join_file): New arg resurrecting. Register with "0" if we are - the server and are resurrecting. - (update_fileproc): Pass the flag from checkout_file to join_file. - -Wed May 22 19:06:23 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (death): Test for above fix, in test 89 and new test 89a. - -Tue May 21 09:49:04 1996 Greg A. Woods <woods@most.weird.com> - - * update.c (update_usage): oops -- fix my spelling typo. - -Mon May 20 10:53:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (find_fileproc): Call freevers_ts. - - * commit.c (find_*): Keep an ignlist, like update.c and client.c do. - * commit.c (commit): Process the files from the ignlists, once we - are connected to the server. - * sanity.sh (ignore): New tests 189e and 189f test for new - commit.c behavior (and client.c behavior, which is unchanged). - * sanity.sh (conflicts): Remove dir1 and sdir in parts of the test - where we aren't prepared for "? dir1" and similar output. - -Mon May 20 13:23:36 1996 Greg A. Woods <woods@most.weird.com> - - * main.c (cmd_usage): minor corrections to descriptions of status, - rtag, tag, and rdiff. Sort alphabetically by command name. - -Mon May 20 10:36:07 1996 Ian Lance Taylor <ian@cygnus.com> - - * client.c (call_in_directory): Move the call to Entries_Close - before the call to chdir, since Entries_Close examines files in - the current directory. - -Fri May 17 12:13:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (start_tcp_server, start_server, start_rsh_server, - read_line, filter_through_gzip, filter_through_gunzip, - call_in_directory): Reindent as needed. - - * main.c (main): Add missing #endif. Use indentation to indicate - nesting. - -Thu May 16 17:15:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (cmd_usage): Add "init" command. - -Thu May 16 16:45:51 1996 Noel Cragg <noel@gargle.rain.org> - - * client.c (start_tcp_server): Error message modified to tell the - user to use ":server:" instead of setting CVS_CLIENT_PORT to a - negative number. - - * main.c (main): Add #ifdefs for turning off buffering of - stdio/stderr, so we don't get it by default. - -Thu May 16 01:29:47 1996 noel <noel@BOAT_ANCHOR> - - * commit.c (commit_filesdoneproc): Print the repository and root - directories as part of the error message. - - * main.c (main): Don't buffer stdout or stderr. It's inefficient, - but it then produces the right output for sanity.sh. - -Thu May 16 09:44:47 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * fileattr.c (fileattr_set): In the case where we are about to - call delproc, don't free ->data; delproc does that. - * sanity.sh (devcom): New tests devcom-b* test for this fix. - - * sanity.sh (conflicts): Remove redundant clean up from previous - tests at the beginning of the test. Use dotest a few more places. - (conflicts2): New test, tests for Ian's fix to Classify_File. - - * client.c (remove_entry_and_file): Add comment about - existence_error's. - -Sat May 16 1996 Ian Lance Taylor <ian@cygnus.com> - - * update.c (update_dirleave_proc): Don't try to chdir .. and check - for an empty directory if there is a slash in the directory name. - -Thu May 16 09:02:59 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (deep): New tests deep-4a* test for Ian's fix to - update_dirleave_proc. - -Sat May 16 1996 Ian Lance Taylor <ian@cygnus.com> - - * main.c (main_cleanup): Report signal name before dying. - -Wed May 15 23:47:59 1996 Noel Cragg <noel@gargle.rain.org> - - * main.c (usg): revert usage strings for `-H' flag change. - -Sat May 15 1996 Ian Lance Taylor <ian@cygnus.com> - - * server.c (serve_static_directory): Return immediately if there - is a pending error. - (serve_sticky): Likewise. - (serve_modified): Read the file data even if there is a pending - error. - -Wed May 15 14:26:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): If -d and CVS/Root both specified, after writing - the value from -d into CVS/Root, use the value from -d, not the - old value from CVS/Root. Don't write CVS/Root with value from -d - until we have verified that it works. - * sanity.sh: Reenable test basica-9 and adjust for new behavior. - -Tue May 14 1996 Jim Kingdon <kingdon@cyclic.com> - - * logmsg.c (do_editor): If user aborts the commit, still remove the - temporary file. - -Tue May 14 11:45:41 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * filesubr.c, cvs.h (cvs_temp_name): New function. Move L_tmpnam - define from cvs.h to filesubr.c. - * client.c, diff.c, import.c, login.c, logmsg.c, no_diff.c, - patch.c, wrapper.c: Call cvs_temp_name not tmpnam. - * login.c (login): Reindent function. - -Tue May 14 10:56:56 1996 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_fast_checkout): If workfile is NULL, don't call chmod. - -Mon May 13 10:52:10 1996 Greg A. Woods <woods@most.weird.com> - - * checkout.c (export_usage): note which options cause a sticky - version to be set, and which option avoids this. - * update.c (update_usage): likewise - -Sat May 11 18:57:07 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Comment out test basica-9 until I get around to - actually fixing it (the -d vs. CVS/Root change broke it). - -Fri May 10 09:39:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): -d now overrides CVS/Root. - -Thu May 9 19:45:24 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c: Remove comment listing commands at beginning. It was - out of date and redundant with the help. - -Thu May 9 09:33:55 1996 Greg A. Woods <woods@most.weird.com> - - * main.c: add 'init' to opening comment listing commands - - * mkmodules.c (init): fix to recognize argc==-1 as hint to call - usage() [should make "cvs init -H" work as expected] - -Wed May 8 15:02:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Set EXPR in the case that the expr in the path is the - one that we want. - -Wed May 8 14:06:24 1996 Greg A. Woods <woods@most.weird.com> - - * sanity.sh (test): - convert all '[' to test ala GCD - -Wed May 8 13:46:56 1996 Greg A. Woods <woods@most.weird.com> - - * sanity.sh (expr): - make a valiant attempt to find GNU expr - - Patch from Larry Jones: - sanity test deep-4 failed with "expr: arg list too long" - sanity test 56 failed because the stderr and stdout output was not - interleaved as expected. - sanity test modules-155a4 failed with "ls: illegal option -- 1" - - * main.c (main): - Patch from Larry Jones for SysV setvbuf - -Tue May 7 16:41:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Increment version number to 1.8.2 to work around fact - that CVS 1.8 (confusingly) calls itself 1.8.1 not 1.8. - -Tue May 7 10:44:20 MET DST 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * rcs.c (rcsvers_delproc): fix memory leak by freeing author - field. - -Mon May 6 10:40:05 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (conflicts): New test conflicts-126.5 tests for bug - which Ian fixed May 5 in update.c - -Mon May 6 06:00:10 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * Version 1.8.1 - -Sun May 5 21:39:02 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * vers_ts.c (Version_TS): If sdtp is NULL, go ahead and check - RCS_getexpand for options. Fixes binaries and non-unix clients. - * sanity.sh: Fix binfiles-5.5 to test for the correct behavior - rather than the buggy behavior which existed when the binfiles-5.5 - test was written. - (binfiles-14c,binfiles-14f): Likewise. - -Sun May 5 17:38:21 1996 Benjamin J. Lee <benjamin@cyclic.com> - - Integrated changes submitted by Ian Taylor <ian@cygnus.com> - - * update.c (update_dirent_proc): cvs co -p doesn't print - anything when run from an empty directory. - - * import.c (import_descend_dir): Check for a file in the - repository which will be checked out to the same name as the - directory. - -Sat May 4 12:33:02 1996 Ian Lance Taylor <ian@cygnus.com> - - Extract the head revision directly from the RCS file when - possible, rather than execing co. - * rcs.c (RCS_reparsercsfile): Set delta_pos field. - (getrcskey): Add lenp parameter. Change all callers. - (RCS_fast_checkout): New function. - (annotate_fileproc): If PARTIAL is not set, just fseek to - delta_pos. - * rcs.h (struct rcsnode): Add delta_pos field. - (RCS_fast_checkout): Declare. - * diff.c (diff_file_nodiff): Call RCS_fast_checkout rather than - RCS_checkout. - * import.c (update_rcs_file): Likewise. - * no_diff.c (No_Difference): Likewise. - * patch.c (patch_fileproc): Likewise. - * update.c (checkout_file): Likewise. - (patch_file): Likewise. - (join_file): Likewise. - -Sat May 4 12:33:02 1996 Ian Lance Taylor <ian@cygnus.com> - - * classify.c (Classify_File): Don't report a conflict for a - pending remove if somebody else has already removed the file. - -Thu May 2 13:34:37 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * Version 1.7.88 - -Thu May 2 01:40:55 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * server.c (HAVE_INITGROUPS): Use initgroups() only if - located by configure, in the event a system has crypt(), but - no initgroups() - -Wed May 01 21:08:21 1996 noel <noel@BOAT_ANCHOR> - - * client.c (filter_through_gunzip): use "gzip -d" instead of - "gunzip," since there's no good reason (on NT at least) to have an - extra copy of gzip.exe copied to gunzip.exe (Arrrrgh! No symbolic - links!). - - * mkmodules.c (init): check to see that we have the correct number - of arguments or print out the usage message (used to be argc > 1, - should be argc != 1, because help forces argc == -1 as a special - case). - -Wed May 1 18:05:02 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basica): When testing rejection of reserved tag name, - use BASE instead of RESERVED. - -Wed May 1 15:15:11 1996 Tom Jarmolowski <tjj@booklink.com> - - * rcs.c (linevector_delete): Only copy up to vec->nlines - nlines, - not to vec->nlines. - -Wed May 1 15:43:21 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcscmds.c (RCS_settag): Instead of reserving all tag names - containing only uppercase letters, reserve only BASE and HEAD. - * sanity.sh (mflag): Revert 26 Mar change; use all-uppercase tag - name again. - -Wed May 1 15:15:11 1996 Tom Jarmolowski <tjj@booklink.com> - - * rcs.c (linevector_add): Move increment of i out of larger - statement, to avoid assumptions about evaluation order. - -Tue Apr 30 15:46:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Version 1.7.87. - - * server.c (check_password): Don't use ANSI string concatenation. - Reindent function. - -Mon Apr 29 10:48:38 1996 Noel Cragg <noel@gargle> - - * root.c (parse_cvsroot): removed "rsh" as an alias to "server" in - the method section. - - * main.c (main): new variable help so we can support the `cvs -H - cmd' convention. Reverts change of 26 Apr 96 which removed this - feature. - -Sun Apr 28 14:57:38 1996 Noel Cragg <noel@gargle> - - * main.c (main): update error message if parse_cvsroot fails. - * server.c (serve_root): same. - (serve_init): same. - - * client.c (start_tcp_server): get rid of the "fall through" - stuff, now that we have access methods. - (start_server): switch off the access method to choose routine - that starts the server. - (start_tcp_server): tofd wasn't getting set to -1 early enough, - because a call to error for bind or gethostbyname might fail and - the subsequent error check to see if the connection had been made - would fail. - - * root.c: new variable method_names for error reporting purposes. - -Sun Apr 28 17:22:15 1996 Noel Cragg <noel@occs.cs.oberlin.edu> - - * server.c: moved kerberos #includes from main.c for the - kserver_authenticate_connection routine. - -Fri Apr 26 07:59:44 1996 Noel Cragg <noel@gargle> - - * server.c (serve_init): use the new return value from - parse_cvsroot. - (serve_root): same. - * main.c (main): same. - - * root.c (parse_cvsroot): fix indentation, add a return value - which tells whether the command succeeded or failed. - - * main.c (main): move the setting of the UMASK environment - variable inside the stuff that gets done if the user is NOT asking - for help, so we don't signal any errors prematurely (don't want to - give an error because we can't parse an environment variable - correctly if the user asks for help). Similar mods for the code - that tries to get the working directory. - - Also make CVSADM_Root a local variable instead of a global, since - its scope is only about 20 lines here! - - * server.c (kserver_authenticate_connection): moved code from - main.c to clean up MAIN. Makes sense, since we already have a - pserver_authenticate_connection. - (pserver_authenticate_connection): rename from - authenticate_connection. - - * main.c (main): reorganized the routine to eliminate variables - help, help_commands, and version_flag. Now the routine is much - clearer, since we don't have to be checking to see if these - variables are set. One behavior that was a bug/feature which is - now gone is an invocation like "cvs -H rtag" -- previously this - would give usage for rtag, but now gives usage for cvs itself. - The first behavior didn't make sense, especially since we say in - the docs that command-line flags are position-specific. *Reverted - Above* - -Thu Apr 25 20:05:10 1996 Noel Cragg <noel@gargle> - - * main.c (main): make sure we have a valid command name before we - do anything else (moved the thing that looks for a command in CMDS - to right after the GETOPT loop). Added `kserver' and `pserver' to - the table so they will be recognized; set their functions to - SERVER so that help will be given when asked for. - - * expand_path.c (expand_variable): return CVSroot_original rather - than CVSroot_directory. - - * main.c (main): save CVSroot in the env rather than - CVSroot_original, since we might not have called PARSE_CVSROOT - (this can happen if we use the -H option to a command). - - * root.c (parse_cvsroot): the parsing method was bogus for - guessing when we had hostnames vs. directories specified. Any - ambiguity should be removed by having the user specify the access - method. If the access method isn't specified, choose - server_method if the string contains a colon or local_method - otherwise. - - * Changed CVSroot_remote back to client_active since the code - reads better. - -Wed Apr 24 17:27:53 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * vers_ts.c (Version_TS): xmalloc enough space (1 more - byte). Thanks to purify! - -Mon Apr 22 00:38:08 1996 Noel Cragg <noel@gargle> - - * create_adm.c (Create_Admin): pass CVSroot_original instead of - CVSroot_directory (oops!). - * update.c (update_filesdone_proc): same. - - * server.c (serve_root): modify to use parse_cvsroot rather than - goofing around with other variables. Will need to fix - parse_cvsroot to have a return value so we can return an error and - quit gracefully if in server mode. - (serve_init): same. - - * main.c: modify command table to remove client_* routines, since - they no longer exist. - (main): don't try to switch off non-existent field in command - table! ;-) - - * client.h (client_*): removed prototypes for now non-existent - functions. - - * client.c: remove proto for get_cvs_password, since it is now in - cvs.h. Modify routines to use new globals that describe CVSROOT - rather than client_active, server_host, server_user, and - server_cvsroot. - (parse_cvsroot): removed function, since a more generic version - now lives in root.c. - (connect_to_pserver): remove call to parse_cvsroot, since main.c - has already done it for us. - (client_*): removed all of these routines, since they only call - parse_cvsroot and then their respective operation functions. - Since main.c has already called parse_cvsroot, we shouldn't bother - with the extra function call, since client-server diffs are - already handled in the core routines themselves. - - * main.c: remove CVSroot as a global variable. Remove - use_authenticating_server variable since we have a new - `CVSroot_method' variable instead. - (main): add `CVSroot' as a local variable. Call parse_cvsroot - after we're sure we have the right setting for `CVSroot.' - - * login.c (login): update to use new global variables. Instead of - old behavior which let the user type in user@host when prompted, - it makes them do it in CVSROOT proper. The routine still lets the - user type the password, however. - (get_cvs_password): make sure that CVSROOT is fully qualified - before trying to find the entry in the .cvspass file. - * cvs.h: add prototype for get_cvs_password. - - * add.c: use new globals that describe CVSROOT. - * admin.c: same. - * checkout.c: same. - * commit.c: same. - * create_adm.c: same. - * diff.c: same. - * edit.c: same. - * expand_path.c: same. - * history.c: same. - * ignore.c: same. - * import.c: same. - * log.c: same. - * mkmodules.c: same. - * modules.c: same. - * parseinfo.c: same. - * patch.c: same. - * rcs.c: same. - * recurse.c: same. - * release.c: same. - * remove.c: same. - * repos.c: same. - * rtag.c: same. - * status.c: same. - * tag.c: same. - * update.c: same. - * watch.c: same. - * wrapper.c: same. - - * root.c (Name_Root): remove error message that reports missing - CVSROOT, since new code in main.c will catch it and also print out - an error. - (parse_cvsroot): new function -- takes a CVSROOT string and breaks - it up into its component parts -- method, hostname, username, and - repository directory. Sets new global variables that describe the - repository location more precisely: CVSroot_original, - CVSroot_remote, CVSroot_method, CVSroot_username, - CVSroot_hostname, CVSroot_directory for use by all other - functions. Checks for obvious errors in format of string. - (main): a short routine to test parse_cvsroot from the command - line. - * cvs.h: add prototype for parse_cvsroot and extern definitions - for new globals. - - * cvs.h: removed CVSroot variable, since we don't want other - routines using the raw CVSROOT (also helped to find all of the - refs to the variable!). - -Fri Apr 19 11:22:35 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * Version 1.7.86 - -Thu Apr 18 1996 Jim Kingdon <kingdon@cyclic.com> - - * client.c (try_read_from_server): Compare return value from fwrite - with a size_t not an int (Visual C++ lint). - -Wed Apr 17 11:56:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (try_read_from_server): New function. - (read_from_server): Use it. - (read_counted_file): New function. - * client.c, server.c: Add Template response. - * cvs.h (CVSADM_TEMPLATE): Added. - * logmsg.c (do_editor): If repository is NULL, use CVSADM_TEMPLATE - file in place of rcsinfo. - * server.c, server.h (server_template): New function. - * create_adm.c (Create_Admin): Call it. - -Tue Apr 16 13:56:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * repos.c (Name_Repository): Fix comments. - * create_adm.c (Create_Admin): Fix indentation. - -Wed Apr 10 16:46:54 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * options.h.in: Include relevant information here rather than - citing (former) FAQ. - - * ChangeLog-9395: Fix typo in introductory paragraph. - -Wed Apr 10 14:55:10 1996 code by Mike Spengler mks@msc.edu - comments by Jim Kingdon <kingdon@harvey.cyclic.com> - - * filesubr.c (unlink_file_dir,deep_remove_dir): Don't call unlink - on something which might be a directory; check using isdir instead. - -Wed Apr 10 14:55:10 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (build_dirs_and_chdir): Pass path, not cp, to - Create_Admin. The former is the correct update dir. - * sanity.sh (modules): New tests modules-155* test, for above fix. - -Mon Apr 8 13:53:27 1996 Samuel Tardieu <sam@inf.enst.fr> - - * rcs.c (annotate_fileproc): If the file is not under CVS control, - return instead of dumping a core. Don't bug on files with an empty - first revision. - -Fri Mar 29 16:08:28 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (annotate_fileproc): If last line of add-chunk is not - newline terminated, end the loop when we find that out. - -Fri Mar 29 16:59:34 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * rcs.c (annotate_fileproc): allow last line of add-chunk not to - be newline terminated - -Thu Mar 28 10:56:36 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - Add more diff tests: - * sanity.sh (basic2): Use dotest for test 61. - (basica): Add test basica-6.2. - (branches): Add tests branches-14.4 and branches-14.5. - (basic1): Remove tests 19, 20, 25, and 26. The only thing this - might miss out on is diff's interaction with added and removed - files, but those tests didn't test that very well anyway. - - * rcs.c (RCS_getrevtime): Add comment regarding years after 1999. - - * rcs.c: Add "cvs annotate" command and related code. - (getrcskey): Move special handling of RCSDESC from here to - callers. Handle those keys (desc, log, text) which do not - end in a semicolon. - * rcs.h (RCSVers): Add author field. - * rcs.c (RCS_reparsercsfile): Set it. - * cvs.h (annotate), main.c (cmd_usage, cmds), client.h client.c - (client_annotate), server.c (serve_annotate, requests): Usual - machinery to add a new command. - * sanity.sh (basica): Test cvs annotate. - - * sanity.sh (branches): More tests, of things like adding files on - the trunk after a branch has been made. - -Tue Mar 26 09:48:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * expand_path.c: Don't declare free and xmalloc; cvs.h already - takes care of that. - - * sanity.sh (mflag): Don't use tag name reserved to CVS. - - NT local changes plus miscellaneous things noticed in the process: - * import.c (add_rcs_file): Use binary mode to write RCS file. Use - \012 where linefeed is intended. Copy data a small block at a - time, until we hit EOF, rather than trying to read the whole file - into memory at once. - * client.c (send_modified): Add comments regarding st_size. - * commit.c (commit): Add comments regarding binary mode and read(). - * logmsg.c (do_editor): Add comments regarding st_size. - * server.c (server_updated): Use binary mode to read file we are - sending. - - * rcscmds.c (RCS_settag): Complain if user tries to add a tag name - reserved to CVS. - * sanity.sh (basica): Test for this behavior. - - * sanity.sh (binfiles): New tests test ability to change keyword - expansion. - -Mon Mar 25 1996 Jim Kingdon <kingdon@cyclic.com> - - * cvs.h, filesubr.c (expand_wild): New function. - * recurse.c (start_recursion): Call expand_wild at beginning and - free its results at the end. - * cvs.h, subr.c (xrealloc): Make argument and return value void *. - * client.h, client.c (send_file_names): Add flags argument. If - SEND_EXPAND_WILD flag is passed, call expand_wild at beginning and - free its results at the end. - * admin.c, add.c, log.c, tag.c, status.c, edit.c, watch.c, - update.c, commit.c, remove.c, client.c, diff.c: Update callers. - -Fri Mar 22 10:09:55 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * error.c (error, fperror): Exit with status EXIT_FAILURE rather - than STATUS. We had been neglecting to check for 256, and the - value of providing a count of errors is probably minimal anyway. - * add.c, modules.c, mkmodules.c, tag.c, server.c, main.c, - import.c, client.c, scramble.c, recurse.c: Exit with status - EXIT_FAILURE rather than 1. On VMS, 1 is success, not failure. - * main.c (main): Return EXIT_FAILURE or 0. The value of providing - a count of errors is minimal. - - * client.c (init_sockaddr): Exit with status 1 rather than - EXIT_FAILURE. The latter apparently doesn't exist on SunOS4. - Reindent function. - -Mon Mar 18 14:28:00 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h, ignore.c: New variable ign_case. - * ignore.c (ign_name): If it is set, match in a case-insensitive - fashion. - * server.c (serve_case): New function. - (requests): Add Case request. - * client.c (start_server): If FILENAMES_CASE_INSENSITIVE is - defined, send Case request. - -Sat Mar 16 08:20:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - For reference, this change takes cvs's text segment from 315392 - bytes to 311296 bytes (one 4096 byte page). - * cvs.h (struct file_info): Add fullname field. - * recurse.c (do_file_proc): Set it. - * commit.c (find_fileproc), client.c (send_fileproc), commit.c - (check_fileproc), diff.c (diff_fileproc), edit.c - (unedit_fileproc), patch.c (patch_fileproc), remove.c - (remove_fileproc), rtag.c (rtag_fileproc), tag.c (tag_fileproc), - update.c (update_fileproc), watch.c (watchers_fileproc): Use it - instead of computing it each time. - * diff.c (diff_fileproc), remove.c (remove_fileproc): Use fullname - where we had been (bogusly) omitting the directory from user - messages. - * edit.c (unedit_fileproc, edit_fileproc): If we cannot close - CVSADM_NOTIFY, mention CVSADM_NOTIFY rather than finfo->file in - error message. - * rtag.c (rtag_fileproc), tag.c (tag_fileproc): Reindent. - -Fri Mar 15 15:12:11 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * server.h: fix prototype of server_pause_check (was - server_check_pause) - -Thu Mar 14 1996 Jim Kingdon <kingdon@cyclic.com> - - * vers_ts.c (Version_TS), entries.c (Scratch_Entry, AddEntryNode): - Change findnode to findnode_fn. - - * main.c: Depending on HAVE_WINSOCK_H, include winsock.h or - declare gethostname. - * cvs.h: Don't declare it here. - -Thu Mar 14 07:06:59 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (find_fileproc): If vn_user is NULL and ts_user is not, - print an error rather than silently succeeding. - * sanity.sh (basica-notadded): New test, for above fix. - (dotest_internal): New function. - (dotest,dotest_fail): Call it instead of duplicating code between - these two functions. - - * sanity.sh: Skip tests binfiles-9 through binfiles-13 for remote. - - * options.h.in: Adjust comment to reflect kfogel change. - -Thu Mar 14 01:38:30 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * options.h.in (AUTH_CLIENT_SUPPORT): turn on by default. - -Wed Mar 13 09:25:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * vers_ts.c (Version_TS): Don't try to override options from rcs - file if there isn't an rcs file (e.g. called from send_fileproc). - This fixes a bug detected by test 59 in "make remotecheck". - - * rcs.c (RCS_reparsercsfile, RCS_getexpand): Assert that argument - is not NULL. - - Fix a gcc -Wall warning: - * rcs.c, rcs.h (RCS_getexpand): New function. - * vers_ts.c (Version_TS): Call it. - * rcs.c (RCS_reparsercsfile): Make static. - - Add a "cvs init" command. This is needed because cvsinit.sh - invoked mkmodules which doesn't exist any more. - * mkmodules.c: Break filelist out of mkmodules function, rename - struct _checkout_file to struct admin_file (for namespace - correctness), and add contents field. - (init,mkdir_if_needed): New functions. - * cvs.h (init): Declare. - * main.c (cmds): Add init. - (main): If command is init, don't require cvsroot to exist. - * client.c, client.h (client_init, send_init_command): New functions. - * client.c (start_server): Don't send Root request if command is init. - * server.c (serve_init): New function. - (requests): Add "init". - -Wed Mar 13 09:51:03 MET 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * vers_ts.c (Version_TS): set options to default option if the - file if no -k option but -A was given. This avoids the (wrong) - update message for binary files which are up-to-date when - running 'cvs -A'. - - * update.c (checkout_file): remove test of -k option stored in the - file itself because it was moved to vers_ts.c - - * sanity.sh: added tests for the above fix. - -Tue Mar 12 13:47:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * hash.c (findnode): Adjust comment regarding errors. - - * hash.c (findnode, findnode_fn): Assert that key != NULL. This - way the check still happens even if the function is later - rewritten to not start out by calling hashp. - -Mon Mar 11 10:21:05 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: If expr accepts multi-line patterns but is too - liberal in matching them, print a warning but keep going. - - * sanity.sh: Add QUESTION variable, analogous to PLUS. Use it - instead of \? to match a question mark. - - * cvs.h (CVSMODULE_OPTS, CVSMODULE_SPEC): Move from here... - * modules.c: ...to here. They are only used here and the code to - handle the syntax of modules files should not be scattered all over. - * modules.c (CVSMODULE_OPTS): Add "+" as first character. - * sanity.sh (modules): New tests 148a0 and 148a1 test for - above-fixed bug. - -Mon Mar 11 13:11:04 1996 Samuel Tardieu <sam@inf.enst.fr> - - * modules.c (cat_module): set optind to 0 to force getopt() to - reinitialize its internal nextchar - -Mon Mar 11 00:09:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * hash.c (findnode, findnode_fn): Revert changes of 7-8 Mar 1996. - The correct style is to assert() that key != NULL (see HACKING), - which is already done in the hashp function. - * fileattr.c (fileattr_delproc): Likewise, assert() that - node->data != NULL rather than trying to deal with it being NULL. - -Fri Mar 8 01:31:04 1996 Greg A. Woods <woods@most.weird.com> - - * hash.c (findnode_fn): one more place to avoid calling hashp() - with a NULL key - -Thu Mar 7 17:30:01 1996 Greg A. Woods <woods@most.weird.com> - - * hash.c (findnode): also return NULL if key is not set - [[ reported by Chris_Eich@optilink.optilink.dsccc.com, and - supposedly in a PR that should be marked "fixed"..... ]] - - * fileattr.c (fileattr_set): set node->data to NULL after freeing - it to prevent subsequent accesses - (fileattr_delproc): don't free node->data if it's NULL, and set it - to NULL after freeing - [[ reported by Chris_Eich@optilink.optilink.dsccc.com, and - supposedly in a PR that should be marked "fixed"..... ]] - -Fri Mar 1 14:56:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basica): New test basica-4a tests for bug fixed by - sam@inf.enst.fr on 1 Mar 96. - -Fri Mar 1 18:10:49 1996 Samuel Tardieu <sam@inf.enst.fr> - - * tag.c (check_fileproc): Check for file existence before trying - to tag it. - -Fri Mar 1 07:51:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (update_entries): If command is export, set options to - NULL. - -Thu Feb 29 16:54:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * lock.c (write_lock, Reader_Lock): Remove - BOGUS_UNLESS_PROVEN_OTHERWISE code. It was pretty bogus, and has - been ifdeffed out for a long time. - * cvs.h (CVSTFL): Removed; no longer used. - - * cvsrc.c, cvs.h (read_cvsrc): Pass in command name rather than - using global variable command_name. - * main.c (command_name): Initialize to "", not "cvs" so that error - messages don't say "cvs cvs". Update calls to read_cvsrc to pass - in command_name or "cvs" as appropriate. - * sanity.sh (basica): New test basica-9 tests for above-fixed bug. - - * lock.c: Rename unlock to lock_simple_remove to avoid conflict - with builtin function on QNX. - -Thu Feb 29 17:02:22 1996 Samuel Tardieu <sam@inf.enst.fr> - - * fileattr.c (fileattr_get): Removed NULL pointer dereference - which occurred in the absence of default attribute. - -Thu Feb 29 07:36:57 1996 J.T. Conklin <jtc@rtl.cygnus.com> - - * rcs.c (RCS_isbranch, RCS_whatbranch): Remove no longer used file - argument, swap order of remaining two arguments to be like other - RCS_* functions. - (RCS_nodeisbranch): swap order of arguments to be like other RCS_* - functions. - * rcs.h (RCS_isbranch, RCS_whatbranch, RCS_nodeisbranch): Update - prototypes for above changes. - * commit.c, rtag.c, status.c, tag.c: Update for above calling - convention changes. - -Thu Feb 29 08:39:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (start_server): Revert changes which claimed to fall - back to a different way of connecting. Add comments explaining - why. (I don't think the changes did what they claimed, anyway). - Use indentation rather than comments to line up #if, #else, and - #endif. - - * patch.c (patch, patch_fileproc): Revert change to add optional - arguments to -c and -u. Optional arguments are evil and in - violation of the POSIX argument syntax guidelines. The correct - way to do this is -C and -U. Also change DIFF back to "diff" in - output (see comments). - - gcc -Wall lint: - * client.c (copy_a_file): Declare p inside the #ifdef in which is - it used. - * commit.c (remove_file): Remove unused variable p. - * commit.c (checkaddfile): Remove unused variables p. - * rcs.c (RCS_isbranch): Remove unused variable p. - * rcs.c: Remove unused declarations and definitions of - parse_rcs_proc, rcsnode_delproc, rcslist, and repository. - * rtag.c (rtag_fileproc): Remove unused variable p. - * patch.c (patch_fileproc): Remove unused variable p. - * tag.c (val_fileproc): Remove unused variable node. - * client.c, import.c, lock.c, server.c: Cast pid_t to long before - passing it to %ld. - - * cvs.h: Don't prototype gethostname; merely declare it (on linux, - second argument is size_t not int). - -Thu Feb 29 10:29:25 MET 1996 Norbert Kiesel (nk) <nk@col.sw-ley.de> - - * sanity.sh: added "cat > /dev/null" to loginfo entry to avoid the - SIGPIPE signal - -Thu Feb 29 10:28:25 MET 1996 Norbert Kiesel (nk) <nk@col.sw-ley.de> - - * patch.c: added new variable diff_opt - (patch): allow optional parameter to -c and -u option, send it to - server - (patch_fileproc): cleaned up the code which prints the current - filename. For "-s" option, print the pathname relative to CVSROOT - instead of just the filename. - - * filesubr.c (xchmod): added cast to shut up gcc - - * cvs.h: added prototype for gethostname - -Thu Feb 29 10:27:25 MET 1996 Norbert Kiesel (nk) <nk@col.sw-ley.de> - - * lock.c (write_lock), (Reader_Lock), import.c (update_rcs_file), - client.c (update_entries), (send_modified), server.c (server), - (receive_file), (server_updated): use %ld for printing pid_t - variables - -Thu Feb 29 02:22:12 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * run.c (run_exec): Added VMS return status support. - -Thu Feb 29 01:07:43 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * client.c (send_to_server): wrtn wasn't being declared under - VMS for some reason. - -Wed Feb 28 23:27:04 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * client.c: Changed #ifdef VMS && NO_SOCKET_TO_FD to - #if defined(VMS) && defined(NO_SOCKET_TO_FD) - -Wed Feb 28 22:28:43 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * build_src.com: Added DCL command procedure to build - and link CVS client for VMS. - -Wed Feb 28 22:07:20 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * client.c: VMS CVS client specific changes. - - Added USE_DIRECT_TCP to allow CVS_PORT to be used to specify - a TCP connection port (no Kerberos). Changed - start_kerberos_server() to start_tcp_server(). - - In copy_a_file(): transform a backup file to have a - VMS-friendly name. - - Added HAVE_CONFIG_H to include "config.h". - - start_server() will starts the first successful of any - mutually exclusive methods of starting the CVS server - which might be enabled. - - Initialized use_socket_style and server_sock for VMS in - start_server(). - -Wed Feb 28 21:49:48 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * find_names.c, recurse.c, cvs.h: Changed Find_Dirs() to - Find_Directories(). - * cvs.h: Added VMS filenames enabled through USE_VMS_FILENAMES - VMS POSIX will require to use the regular CVS filenames - while VMS is #define'd. - -Wed Feb 28 21:26:22 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * ignore.c: Added the patterns *.olb *.exe _$* *$ to default - ignore list for VMS. - -Wed Feb 28 13:32:28 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * logmsg.c (do_editor): Fix indentation. - -Wed Feb 28 12:56:49 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * logmsg.c (do_editor): If no editor is defined, exit and print - a message. - -Wed Feb 28 10:40:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * vers_ts.c (time_stamp, time_stamp_server): Reindent and revise - comments. - -Tue Feb 27 23:57:55 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * vers_ts.c: gmtime() returns NULL on some systems (VMS) - revert to local time via ctime() if GMT is not avaiable. - -Tue Feb 27 13:07:45 1996 J.T. Conklin <jtc@rtl.cygnus.com> - - The changes listed below cause cvs to parse each rcs file (and - free the associated rcsnode after the file has been processed) - sequentially. cvs used to parse all files in a directory, an - approach that does not scale to huge repositories with lots - of revisions/branches/tags/etc. - - * cvs.h (struct file_info): Removed srcfiles field. Added rcs - (node) field. - * recurse.c (do_recursion): Removed code that pre-parsed all - rcs files in the directory. - (do_file_proc): Parse current rcs file. - * rcs.c (RCS_parsefiles, parse_rcs_proc, RCS_addnode): Removed. - (RCS_isbranch, RCS_whatbranch): Changed srcfiles argument to - rcs (node). - * rcs.h (RCS_parsefiles, RCS_addnode): Removed prototypes. - (RCS_isbranch, RCS_whatbranch): Updated prototypes. - * add.c, admin.c, checkin.c, checkout.c, classify.c, client.c, - commit.c, diff.c, history.c, import.c, log.c, patch.c, remove.c, - rtag.c, status.c, tag.c, update.c, vers_ts: Updated for above - calling convention / data structure changes. - -Mon Feb 26 16:07:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Version 1.7.3. - - * Version 1.7.2. - -Mon Feb 26 1996 Jim Kingdon <kingdon@cyclic.com> - - * recurse.c (start_recursion): Use last_component rather than - checking for '/' directly. - (do_dir_proc): Likewise. - - Visual C++ lint: - * client.c (send_to_server): Change wrtn to size_t. - (connect_to_pserver): Put tofd and fromfd declarations inside - #ifndef NO_SOCKET_TO_FD. - * scramble.c (shifts): Change from array of char to array of - unsigned char. - -Mon Feb 26 13:31:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (check_repository_password): Remove unused variables - linelen, ch. - - * client.c (send_file_names): Translate ISDIRSEP characters to '/'. - -Sat Feb 24 21:25:46 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (safe_location): Re-indent one line. - -Sat Feb 24 10:50:42 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * checkout.c (safe_location): put assignment to hardpath[x] in an - `else'-clause, so we don't do it when x == -1. - -Sat Feb 24 01:40:28 1996 Marcus Daniels <marcus@sayre.sysc.pdx.edu> - via Karl Fogel <kfogel@floss.red-bean.com> - - * server.c (check_repository_password): Return by reference an - optional username, the `host_user', from the passwd file. The - host_user will be the user-id under which the cvs repository is - run. - (check_repository_password): Use `read_line' instead of fgets to - allow for passwords larger than 32 characters, as well as the - optional host user argument. - (check_password): Modify to use host_user. - (authenticate_connection): Modify to use host_user. - -Sat Feb 24 01:05:21 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * scramble.c (descramble): just shift descrambled string to get - rid of tag char, instead of allocating a whole new copy. - (scramble): cast return value of xmalloc to avoid unsightly - compiler warnings. - - * options.h.in (RCSBIN_DFLT): don't refer to AUTH_SERVER_SUPPORT - in comment anymore, now that it's not defined in this file. - -Fri Feb 23 1996 Jim Kingdon <kingdon@cyclic.com> - - * client.c: Ifdef HAVE_WINSOCK_H, include winsock.h - instead of sys/socket.h and friends. - * login.c: Don't include sys/socket.h and friends. - * login.c (login): Only fclose fp in the case where it was - successfully fopen'd. - * login.c: Declare getpass. - * filesubr.c, cvs.h (get_homedir): New function. - * cvsrc.c, expand_path.c, history.c, login.c: Call it instead - of getenv ("HOME"). - -Fri Feb 23 09:23:20 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (connect_to_pserver): Remove unused variable host. - * login.c: Include getline.h. - (login): Remove unused variables i and username. - (get_cvs_password): Move free of linebuf to where it actually will - be called. Add a "return NULL" at the end of the function to shut - up gcc -Wall. - - * options.h.in: Remove AUTH_SERVER_SUPPORT. - * client.h (authenticate_connection): Declare. - * scramble.c (scramble): Cast char to unsigned char before using - it to look up in table (char might be signed). - * server.c [AUTH_SERVER_SUPPORT]: Include grp.h - (authenticate_connection): Remove unused variables len and - server_user. - - * sanity.sh (basica): Add comments regarding creating a top-level - directory. - (basic1): Don't try to remove first-dir and - ${CVSROOT_DIRNAME}/first-dir at start of test; tests are now - responsible for cleaning up at the end. - (PLUS,DOTSTAR,ENDANCHOR): Add comments regarding fixed GNU expr. - -Thu Feb 22 22:34:11 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h: Remove alloca cruft. - -Wed Feb 21 07:30:16 1996 J.T. Conklin <jtc@rtl.cygnus.com> - - * modules.c (do_module): call free_cwd before exiting. - - * recurse.c: Removed entries global variable. - (do_recursion): Declare entries. Moved call to Entries_Close so - entries list is closed on all code paths. - (start_recursion): Removed call to Entries_Close, entries list has - been moved to do_recursion only. - -Tue Feb 20 22:10:05 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (update_dirent_proc): If dir lacks a CVS subdirectory, - don't recurse into it. - * sanity.sh (conflicts): Test for above-fixed bug. - - * update.c (merge_file): Use write_letter not printf. - -Tue Feb 20 12:34:07 EST 1996: Gary Oberbrunner <garyo@avs.com> - and Jim Kingdon <kingdon@cyclic.com> - - * history.c (history_write): Change username to char * and call - getcaller() to set it. Setting username accidentally got deleted - 8 Feb 96. - * sanity.sh: Revise test 64 to test for above-fixed bug. - * sanity.sh (PLUS): New variable, work around yet another GNU expr - bug. - -Tue Feb 20 14:07:50 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Merge test rtags into test basic2. They never were - capable of running separately of each other. - - * sanity.sh (deep): New test, to test ability to operate in deeply - nested directories (more quickly than basic2 test did). - (basic2,rtags): Remove directories dir3 and dir4. Remove file8, - file10, file12, file9, file11, file13, file15, file16, file17. - These additional files slowed down the tests considerably without - significantly increasing coverage. - - * sanity.sh (PROG): New variable. Use it instead of "cvs" - to match the name cvs prints out for itself. - -Mon Feb 19 09:00:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - This fixes a bug whereby old default attributes would get - clobbered instead of added to on "cvs watch add". - * hash.c (findnode): Don't check for key == NULL; let the - assertion in hashp take care of it. - * fileattr.h, fileattr.c (fileattr_get): If filename is NULL, - return default attributes. - - * client.c (send_repository): Fix indentation. - -Mon Feb 19 01:10:01 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * login.c (login): print out full repos so user knows which server - she's logging into. - - * client.c (send_repository): die if `repos' is NULL. This is a - lame solution; see comments in code. - -Thu Feb 15 15:04:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * error.c (error): Free entire and mess when done with them. - - * sanity.sh (info): Correct syntax of .cvsrc file. - - * cvs.h, expand_path.c, edit.c, parseinfo.c, wrapper.c: - expand_path now takes arguments containing file and line for error - message, and it prints the error message itself. - * sanity.sh (info-6a): Test printing of error message. - - * expand_path.c (expand_variable): Add USER internal variable. - * sanity.sh (info): Test USER and CVSROOT internal variables too. - -Wed Feb 14 19:11:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (usg): Add -s option. - -Tue Feb 13 20:26:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - gcc -Wall lint: - * mkmodules.c (mkmodules_usage): Remove declaration of - non-existent function. - * cvs.h (mkmodules): Declare. - -Mon Feb 12 12:20:04 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * mkmodules.c: Rename main to mkmodules and remove various pieces - of scaffolding which it used to emulate non-existent parts of CVS. - Change calling convention to just take a char * not argc,argv. - Save and restore working directory. - * commit.c (commit_filesdoneproc): Call it if checking files into - CVSROOT. - * Makefile.in (SOURCES): Add mkmodules.c. - (OBJECTS): Add mkmodules.o. - (MSOURCES,MOBJECTS): Removed. - (COMMON_OBJECTS): Removed; move former contents into OBJECTS. - Update other rules accordingly. - * sanity.sh: Adjust to reflect nonexistence of mkmodules. - - These changes introduce functions cvs_output and cvs_outerr; - eventually all server output will go through them rather than - stdio directly. - * server.c (saved_output, saved_outerr): New variables. - (do_cvs_command): Initialize them. - (buf_output): Don't require that buf->output be set; saved_* use - this to shove some data in a buffer which buf_copy_lines will - later want to get data from. - * server.c, cvs.h (cvs_output, cvs_outerr): New functions. - * mkmodules.c (cvs_outerr): New function, so error() works. - * error.c: Reindent. Don't declare program_name and command_name; - cvs.h declares them. - (error): Use vasprintf and cvs_outerr (or fputs in the - error_use_protocol case) rather than stdio directly. - * import.c (import_descend_dir): Remove kludge which had prevented - messages from error() from being out of order with respect to - messages from printf; cvs_output and cvs_outerr are a cleaner - solution to the problem. - (add_log, import): Use cvs_output not printf. - * update.c (write_letter): Use cvs_output not printf. - (checkout_file): Use write_letter not printf. - * sanity.sh: Use dotest for test 56 (test that output is actually - correct). In theory should test that the import.c bug is fixed, - but I was unable to reproduce the bug (it is timing dependent). - -Mon Feb 12 16:07:45 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * commit.c: define last_register_time - (commit): make sure cvs doesn't exit in the same second it wrote - the last timestamp - (commit_fileproc): set last_register_time - (finaladd): set last_register_time - - * run.c, cvs.h: Changed more Popen() to run_popen() - -Mon Feb 12 03:06:50 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * release.c, rtag.c, tag.c: changed 'delete' to 'delete_flag' - to avoid symbol collision with DEC C RTL function delete() - -Mon Feb 12 03:01:48 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * mkmodules.c: changed 'void Lock_Cleanup()' to 'void static - Lock_Cleanup() to avoid conflict with more substantial - Lock_Cleanup() in lock.c - -Mon Feb 12 02:50:19 1996 Benjamin J. Lee <benjamin@cyclic.com> - - * edit.c, logmsg.c, release.c, run.c: Changed Popen() to - run_popen(). VMS' linker is not case sensitive and considered - popen() and Popen() to be identical symbols. - -Sun Feb 11 10:51:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main) [!CLIENT_SUPPORT]: Silently ignore gzip level - rather than printing usage message. - - * cvs.h, expand_path.c (variable_list): New variable. - (variable_set): New function. - * hash.h (enum ntype), hash.c (nodetypestring): Add VARIABLE. - * expand_path.c (expand_path, expand_variable): Reindent. - (expand_variable): Use user variables not environment variables - for ${=VAR} syntax. The environment variables didn't work - client/server. - * main.c (main): Process new -s global option. - * client.c (send_variable_proc): New function. - (start_server): Call it, to send user variables. - * server.c (serve_set): New function. - (requests): Add Set request. - * sanity.sh: Revise info test to use user variables rather than - environment variables. - -Sat Feb 10 16:55:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - By itself this is only a small cleanup, but in the long run it - will be way cool (for reference, it takes CVS's text segment from - 290816 bytes to 294912, which I expect will be made up by future - changes which this enables): - * cvs.h (struct file_info): Added. - (FILEPROC): Replace 5 args with single struct file_info *. - * recurse.c (do_file_proc): Adjust args to fileproc; passed in - instead of from globals. - (do_recursion): Call do_file_proc accordingly. Remove srcfiles - global variable. - * update.c (update_fileproc): Renamed from update_file_proc. - * admin.c, client.c, commit.c, diff.c, edit.c, log.c, patch.c, - remove.c, rtag.c, status.c, tag.c, update.c, watch.c: Update - fileprocs to new calling convention. - -Fri Feb 9 15:30:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * expand_path.c (expand_variable): Accept a variable name starting - with '=' as a way to specify an environment variable. - * sanity.sh (info): New tests, for above behavior. - - * Makefile.in (clean): Also remove check.log check.plog. - - * import.c (comtable): Remove SYSTEM_COMMENT_TABLE; the table - should *not* depend on what kind of machine the server happens to - be. Add "mak", "rc", "dlg", "frm", and "bas" types which were - formerly included via SYSTEM_COMMENT_TABLE. - - * cvs.h, rcs.h, add.c, checkin.c, classify.c, commit.c, diff.c, - import.c, patch.c, rcs.c, update.c, vers_ts.c: Remove - DEATH_SUPPORT ifdefs. They were introduced to facilitate merging - between Cygnus and Berliner variants of CVS, not because it was - intended to subset CVS this way. And they clutter up the code - quite a bit. - * cvs.h, create_adm.c, main.c, update.c: Likewise, remove - CVSADM_ROOT ifdefs (it is still a #define, of course). I believe - they had a more-or-less similar motivation. - - * sanity.sh: Move setting of HOME from ignore test to the start of - the tests so it applies to all tests. - (CVS): Remove -f; the above change takes care of it. - - * rcs.h (RCS_MERGE): Removed; unused. - - * commit.c (checkaddfile): Fix memory leak. - - * admin.c, commit.c, diff.c, log.c, mkmodules.c: Pass -x,v/ to RCS - commands. - - * rcscmds.c, cvs.h (RCS_checkin): New function. - * checkin.c, commit.c, import.c: Call it, rather than run_*. - * cvs.h, commit.c: Remove DEATH_STATE define; the behavior - which used to be the default (DEATH_STATE) is now the only one. - Failing to define DEATH_STATE has been commented as obsolete at - least since CVS 1.5. We still can read repositories created with - such a CVS, however. - * rcs.h, rcs.c: Adjust comments regarding DEATH_STATE. - * subr.c (make_message_rcslegal): Add comment, describing - allocation of returned value. - -Fri Feb 9 09:53:44 MET 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * sanity.sh: use "${testcvs}" instead of "cvs" in devcom tests - - * hash.c: fix "dereferencing a NULL pointer" bug triggered with - "cvs watch add" - (findnode): return NULL if key == NULL - (hashp): assert (key != NULL) - -Fri Feb 9 00:46:47 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_reparsercsfile): Remove unused variable date. - - * myndbm.c (mydbm_load_file): Fix typo ('015' -> '\015'). - -Thu Feb 8 13:00:00 1996 Jim Kingdon <kingdon@peary.cyclic.com> - - * rcs.c (RCS_parse, RCS_parsercsfile, RCS_reparsercsfile), - fileattr.c (fileattr_read), myndbm.c (myndbm_open): - Use FOPEN_BINARY_READ. - * fileattr.c (fileattr_write), myndbm.c (myndbm_close): - Use FOPEN_BINARY_WRITE. - * history.c (history_write, read_hrecs): Specify OPEN_BINARY. - * rcs.c: Remove calls to abort. - * myndbm.c (myndbm_load_file): Ignore CRs from ends of lines - if present. - * myndbm.c, fileattr.c: While I am at it, change \n to \012 - a few places where LF is intended. - * history.c (history_write): Use getenv ("HOME"), not getpwnam, - to find home directory. If it isn't set, just keep going; don't - print a message. - * rcscmds.c, cvs.h (RCS_checkout): New function. - * update.c, checkin.c, commit.c, diff.c, import.c, no_diff.c, - patch.c: Call it instead of run_*. - * patch.c (patch_fileproc): Clean up inconsistent handling of - noexec flag. - * rcscmds.c (RCS_*): Pass -x,v/ to RCS commands; elsewhere in - CVS it is assumed that ,v is a suffix. - -Fri Feb 2 14:07:32 1996 J.T. Conklin <jtc@rtl.cygnus.com> - - * rcs.h (struct rcsnode): Remove dates field (list of rcsversnodes - indexed by date). CVS maintained this list for each RCS file even - though it was never used. This resulted in higher then necessary - memory requirements (and run time too). Even if revision info was - needed, CVS' List data structure is inappropriate because can't - handle duplicate keys. The above was discovered by tracking down - a memory leak. - * rcs.c (RCS_reparsercsfile): Don't build dates list. - (freercsnode): Don't delete dates list. - (rcsvers_delproc): Free date field. - (null_delproc): Removed. - -Thu Feb 1 12:28:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * remove.c (cvsremove): Don't tell user the name of the program - which they use to remove files; we don't have any way of knowing - that, and besides which they might use a GUI or emacs 'dired' anyway. - * update.c (update_filesdone_proc, update_dirleave_proc): Call - unlink_file_dir instead of rm -rf. - * options.h.in: Remove RM; no longer used. - - * sanity.sh: New tests devcom-a* test "cvs watch add", - "cvs watch remove", and "cvs watchers". - - * sanity.sh: New test 171a0 tests for watch.c bug just fixed by kfogel. - - * Most .c files: Remove rcsids. - * cvs.h: Remove USE macro. - -Thu Feb 1 13:07:15 1996 J.T. Conklin <jtc@rtl.cygnus.com> - - * tag.c, rtag.c: Update various comments to reflect function name - changes. - -Thu Feb 1 14:14:31 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * recurse.c (do_recursion): comment #endif. - - * edit.c (notify_check): surround with #ifdef CLIENT_SUPPORT; else - CVS won't compile if CLIENT_SUPPORT is undefined. - - * edit.h (notify_check): surround declaration with #ifdef - CLIENT_SUPPORT. - - * watch.c (watch): if argc <= 1, then just give usage (previously - was "argc == -1"). - -Thu Feb 1 12:28:33 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * README-rm-add: Remove information which is now in cvs.texinfo. - - * sanity.sh: Remove basic0 tests. Move a few to new tests - basica-1a* (but there is no need to test that *every* command - gracefully does nothing on an empty directory; exhaustive testing - is impractical and the generic recursion processor handles this - anyway). - - * sanity.sh: New tests 69a* test use of update -p to restore old - version of dead file. - -Wed Jan 31 18:32:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * ChangeLog-9395: Remove duplicate entries from 1996 which - accidentally got into this file. - - * client.c (read_line, read_from_server): Change "premature end of - file from server" message to "end of file from server (consult - above messages if any)" because 99% of the time it means rsh has - printed an error message and exited. - -Wed Jan 31 15:09:51 1996 J.T. Conklin <jtc@rtl.cygnus.com> - - * edit.c (ncheck_fileproc): Fix memory leak; free line before - returning. - -Tue Jan 30 18:06:12 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * recurse.c (do_recursion): Add comment about the fact that we - don't have locks in place at certain points. - -Tue Jan 30 09:43:34 1996 Vince Demarco <vdemarco@bou.shl.com> - - * edit.c (notify_proc): have notify_proc call expand_path with - the name of the filter program. The user may have used a - cvs environmental variable. (Popen will expand it, but it may not - use the correct value) - -Tue Jan 30 09:43:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * ChangeLog: take the pre-1996 changes and put them in a new file - ChangeLog-9395. - * ChangeLog-9194: Renamed from ChangeLog.fsf. - * ChangeLog-9194, ChangeLog-9395, ChangeLog: Add additional text - explaining the difference between all these logs and pointing to - older logs. - * Makefile.in (DISTFILES): Add ChangeLog-9194 and ChangeLog-9395; - remove ChangeLog.fsf. - - * modules.c (do_module): Don't fall through from 'l' to 'o' case - of option processing switch statement. - -Tue Jan 30 06:50:19 1996 J.T. Conklin <jtc@rtl.cygnus.com> - - * client.c (send_repository): Fix memory leak; free adm_name - before returning. - * diff.c (diff_file_nodiff): Fix memory leak; free xvers before - returning. - * rtag.c (rtag_fileproc): Fix memory leak; if branch_mode is set, - free rev before returning. - * status.c (status_fileproc, tag_list_proc): Fix memory leak; free - return value of RCS_whatbranch. - * tag.c (tag_fileproc): Fix memory leak; free vers before - returning. - (val_fileproc): Fix memory leak; free return value of RCS_gettag. - * watch.c (watch_modify_watchers): Fix memory leak; free mynewattr - before returning. - -Tue Jan 30 09:43:34 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * lock.c (readers_exist): If stat gave an error, print an error - message saying it was from stat, rather than from "reading - directory". Skip the message completely if it was an - existence_error. - - * sanity.sh (branches): New tests (branches off of branches, etc.). - -Tue Jan 30 11:55:34 MET 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * main.c (main): Add change to run getopt_long twice again. - -Mon Jan 29 15:59:31 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - gcc -Wall lint: - * client.c: Include edit.h - -Sun Jan 28 09:45:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * edit.c, edit.h (mark_up_to_date): New function, to remove file - in CVS/Base. - * client.c (update_entries): Call it if file is up to date. - * checkin.c (Checkin): Call it in non-server (local) case. - * sanity.sh: New test 182.5, tests for above-fixed bug. - -Sun Jan 28 01:07:22 1996 Jim Kingdon (kingdon@beezley) - - * client.c (change_mode): Separate out CHMOD_BROKEN code to parse - mode_string, rather than going through a mode_t. Cleaner than - the previous CHMOD_BROKEN code (which also had a typo of && not &). - -Sat Jan 27 23:29:46 1996 Jim Kingdon (kingdon@beezley) - - * edit.c (edit_fileproc): Check for EACCESS as well as EEXIST. - -Sat Jan 27 16:26:30 1996 Karl Fogel (kfogel@floss.cyclic.com) - - * client.c (notified_a_file): use rename_file() instead of - rename() (but temporarily set `noexec' to 0 so it runs - unconditionally). - (change_mode): deal with CHMOD_BROKEN. - -Fri Jan 26 00:14:00 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * server.c: renamed `dirname' to `dir_name', to avoid conflicts - with system headers. - - * client.c: renamed `dirname' and `last_dirname' to `dir_name' and - last_dir_name' (see above). Not strictly necessary, but - consistency is nice -- as long as you do it all the time. - -Thu Jan 25 00:41:59 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * options.h.in (AUTH_SERVER_SUPPORT, AUTH_CLIENT_SUPPORT): change - comment now that no longer under construction. - -Wed Jan 24 15:25:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Version 1.7.1. - - * Version 1.7. - -Sat Jan 20 00:05:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Version 1.6.87. - -Mon Jan 15 18:14:55 1996 Gary Oberbrunner <garyo@avs.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * tag.c (val_direntproc): New function to ignore - nonexistent dirs when recursing to check tag validity. - (tag_check_valid): Pass it to start_recursion. - * sanity.sh (death): New tests 65a0-65a6 cause test 74 to test for - above-fixed bug. - -Mon Jan 15 12:55:37 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c: Revert change to run getopt_long twice. This can go in - after 1.7. - -Mon Jan 15 13:03:28 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * filesubr.c (deep_remove_dir): added test of EEXIST for nonempty - directory (Posix states that both ENOTEMPTY (BSD) and EEXIST - (SYSV) are valid) - - * main.c (main): run getopt_long twice to allow command-line - suppression of reading the cvsrc file - -Fri Jan 12 10:02:43 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Version 1.6.86. - -Thu Jan 11 23:28:05 1996 J.T. Conklin <jtc@rtl.cygnus.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * fileattr.h (fileattr_startdir): Add comment about REPOS == NULL. - * fileattr.c (fileattr_read, fileattr_write): Assert that - fileattr_stored_repos != NULL. - (fileattr_free): If fileattr_stored_repos is NULL, don't free it. - -Thu Jan 11 18:03:21 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * scramble.c (descramble): deal with DIAGNOSTIC better. - -Thu Jan 11 12:04:42 1996 Norbert Kiesel <nk@col.sw-ley.de> - - * main.c: remove CVS_NOADMIN. - - * options.h.in: remove CVS_NOADMIN - -Thu Jan 11 10:28:44 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * scramble.c (descramble): make sure the string returned is safe - to free(). - -Wed Jan 10 01:11:23 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (serve_notify): Cast return value from malloc. - - * edit.c (notify_do): Use struct assignment, not struct - initialization (which SunOS4 /bin/cc doesn't have). - -Tue Jan 9 09:41:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Version 1.6.85. - - We use version numbers instead of patchlevels. But there was some - confusing patchlevel stuff lying around. Nuke it: - * Makefile.in (HEADERS): Remove patchlevel.h - * patchlevel.h: Removed. - * main.c: Don't include patchlevel.h. - (main): Don't print patch level. - - * server.c (check_repository_password): Check for errors from - system calls; reindent function. - -Tue Jan 9 23:15:30 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * expand_path.c: fix comments (explain expand_path()'s behavior - correctly). - -Tue Jan 9 09:41:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * edit.c (notify_proc): After copying in string following %s, - don't clobber it. Instead set up q to end of string. - - * watch.c (watch_modify_watchers), edit.c (editor_set): Fix sense - of test in trying to decide whether attributes are changed. - - * cvs.h (CVSROOTADM_USERS): New macro. - * edit.c (notify_do): Look up notifyee in CVSROOTADM_USERS if it - exists. - -Tue Jan 9 21:39:45 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * expand_path.c: don't redundantly #include things that cvs.h - already #includes (i.e., stdio.h, ctype.h, string[s].h). - -Tue Jan 9 09:41:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * ignore.c (ign_default): Add *.obj. - - * server.c: Put /* */ around #endif comment. - -Mon Jan 8 20:37:17 1996 Karl Fogel <kfogel@floss.red-bean.com> - - * client.c (connect_to_pserver): check return value of recv(). - -Mon Jan 8 11:37:57 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (connect_to_pserver): Check for error from connect; - reindent function. - - * sanity.sh (4.75): Use dotest, so we get a PASS if test passes. - - * sanity.sh (dotest): New argument OUTPUT2. - (188a): Use it instead of \|. - - * sanity.sh (import): Avoid using string $ followed by Id followed - by $ in sanity.sh source, in case sanity.sh itself is under CVS. - I hate keyword expansion. - - * sanity.sh: If expr cannot handle multiline expressions, fail and - tell the user to get one which can. - - * release.c (release_delete): Remove unused variable retcode. - -Fri Jan 5 13:30:00 1996 Jim Kingdon <kingdon@peary.cyclic.com> - - * release.c (release_delete): Call unlink_file_dir rather - than "rm -rf". - -Thu Jan 4 09:58:30 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (find_fileproc): Print "nothing known about foo" and - return 1 if the file doesn't exist and isn't in CVS/Entries. - (commit): If the recursion over find_fileproc returns an error, - print "correct above errors first!" just like local CVS. - * sanity.sh (basica): Test for above-fixed bug. - - * release.c (release): If we are the client, only unedit if the - server supports it. - - * sanity.sh: Remove STARTANCHOR stuff; expr patterns are - automatically anchored to the start. ENDANCHOR remains. - - * commit.c (commit): Don't start the server until we have - determined that there is something to commit. - -Thu Jan 4 09:48:33 1996 Ben Laurie <ben@gonzo.ben.algroup.co.uk> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (start_server): dup the file descriptor before - fdopening it. - -Wed Jan 3 18:25:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Remove tests 5, 5.5, and 5.75. All that stuff is - tested elsewhere. - - * ignore.c (ign_default): Change CVS* to CVS CVS.adm. CVS* is too - broad, especially in a case-insensitive filesystem. - - * Makefile.in (cvsbug): version.c is in srcdir. - -Wed Jan 3 17:30:45 1996 Phi-Long Tran <ptran@autodesk.com> - - * modules.c (do_module): Honor error_use_protocol in printing trace. - * server.c (server_register): Move check for options NULL to above - printing of the trace. - -Wed Jan 3 01:19:53 1996 Mark Immel <immel@centerline.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (checkout_file): Do not resurrect file on join if it - doesn't contain the revisions we are joining. Probably not a - perfect test, but should be an improvement. - * sanity.sh (death): New death-file4-* tests, for bug fixed above. - -Wed Jan 3 01:19:53 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c, admin.c, checkout.c, client.c, commit.c, diff.c, edit.c, - history.c, import.c, log.c, patch.c, release.c, remove.c, rtag.c, - status.c, tag.c, update.c, watch.c: In calling send_to_server, - pass \012 not \n. On the Mac \n is CR, not LF, and we want to - send LF. I didn't try to deal with whether files in CVSADM should - contain CR or LF--in fact there is some code in client.c which - reads \n from CVSADM files and passes it to send_to_server; it - needs to be cleaned up one way or the other. - - * entries.c (Entries_Open): Don't try to close fpin twice. - - * client.c (update_entries): Fix typo ("strlen (filename + 10)" - -> "strlen (filename) + 10"). - - * commit.c (checkaddfile): Remove arbitrary limit. - -Tue Jan 2 11:25:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (commit): Only pass files which were modified, added, - or removed to send_file_names. This has as a side effect a - semantic change--the up-to-date check is now skipped for other - files--but probably a good one, or at least not a bad one. - * sanity.sh (basica): New test; tests for bug fixed above. - * sanity.sh (187a3): Adjust for new 'cvs commit' output. Set up - DOTSTAR to match arbitrary text (another GNU expr bug/misfeature, - sigh). - - * sanity.sh: Test that the commit in test 43 actually worked. - Merge tests basic2 and basic3 and make them independent of basic1. - (pass,fail): Don't insert spurious space. - (45.5): Fix typo in directory name. - -Tue Jan 2 13:00:00 1996 Jim Kingdon <kingdon@peary.cyclic.com> - - Visual C++ lint: - * myndbm.c: Prototype write_item. - -Tue Jan 2 11:25:22 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - gcc -Wall lint: - * client.c (client_expand_modules): Pass error message not "" to error. - * client.c (supported_request), server.c (supported_response): - Return a value (gcc -Wall can't know that error doesn't return). - * commit.c (copy_ulist): Return a value. - * history.c (fill_hrec): Don't make assumptions about whether - time_t is "int" or "long" or what. - * cvs.h: Declare link_file. - * server.c: Include fileattr.h. - * server.c (server_notify): Remove unused variable val. - * tag.c (val_fileproc): Remove unused variable foundtag. - -Mon Jan 1 09:49:16 1996 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Version 1.6.5. - - * Version 1.6.4. - - * filesubr.c (link_file): Add comment about link vs. copy semantics. - - * cvs.h (struct vers_ts): Fix comments. - * commit.c (commit): Before we ask for a log message, figure out - what is modified and what is not and pass the information to - do_editor. - (copy_ulist,find_fileproc): New helper functions for above code. - - * client.c (read_line): When writing to from_server_logfile, write - the \n too. - - * client.c (send_files): No longer call send_file_names. - * client.h: Update comment. - * add.c, admin.c, commit.c, diff.c, edit.c, log.c, remove.c, - status.c, tag.c, update.c, watch.c: Call send_file_names before - send_files. - * client.c: New variables module_argc, module_argv. - (client_expand_modules): Set them, to arguments. - (client_send_expansions): Use them instead of modules_vector to - send arguments. - * sanity.sh (modules): Add test of modules -d flag. - - -For older changes see ChangeLog-9395. diff --git a/contrib/cvs/src/ChangeLog-97 b/contrib/cvs/src/ChangeLog-97 deleted file mode 100644 index ce7180b..0000000 --- a/contrib/cvs/src/ChangeLog-97 +++ /dev/null @@ -1,3249 +0,0 @@ -1997-12-30 enami tsugutomo <enami@but-b.or.jp> - - * rcs.c (RCS_checkin): Use gmtime() instead of localtime() - (restores behavior from RCS 5.x which was broken with RCS library - -kingdon). - -Mon Dec 29 12:53:00 1997 Ian Lance Taylor <ian@cygnus.com> - - * modules.c (do_module): Check for a request for a file within a - module which is not a directory. - * sanity.sh (modules): Add test 149b1 for above patch. - - * client.c (start_tcp_server): Remove useless assignment, left - behind by Dec 15 patch. - -Sat Dec 27 17:41:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c, options.h.in, history.c, import.c, main.c, rcs.c, - update.c: Remove !HAVE_RCS5 code. It had bit-rotted a while ago, - and more to the point is obsolete with the RCS library. - -27 Dec 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * zlib.c, server.h (gunzip_and_write): New function. - * client.c (update_entries): Call it instead of a gunzip subprocess. - * zlib.c, server.h (read_and_gzip): New function. - * client.c (send_modified): Call it instead of a gzip subprocess. - -Sat Dec 27 13:07:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - Decrease RCS_deltas memory usage to what we need (approximately - the size of the file we are patching plus the size of the largest - patch). Previously memory usage had been approximately the size - of the RCS file because we never freed lines until the end. - * rcs.c (linevector_free, linevector_copy, linevector_add, - linevector_delete): - Instead of having all the lines and struct line's in the alloc_* - space, have each line and its struct line in its own malloc'd - space. Use a refcount to deal with curlines vs. headlines - vs. trunklines in RCS_deltas. - (struct allocblock, blocks, block_alloc, block_free): Remove; no - longer used. - (apply_rcs_changes, RCS_deltas): Don't copy lines into allocated - space; linevector_add now does that for us. - (rcs_change_text, RCS_deltas): Don't call block_free. - -Tue Dec 23 08:28:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvsbug.sh: Change bug-cvs address from prep.ai.mit.edu to gnu.org - per email from Martin Hamilton. - -Sun Dec 21 21:49:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_checkin): Disable keyword expansion when generating - the change text. - * sanity.sh: Move tests keyword-24 through keyword-27 into - new section keywordlog and expand greatly. Note that CVS 1.9.18 - passes the new tests both local and remote but the current - version failed them both local and remote before this fix. - -Sat Dec 20 19:56:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_delete_revs): Clean up temporary files even if noexec. - Without this fix, basica-o5a in sanity.sh would leave files around. - -Thu Dec 18 13:05:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * run.c: Fix typo in declaration (evecvp -> execvp) (credit to - Erik Walthinsen for reporting this). Only declare it if not - HAVE_UNISTD_H. Move declaration to before the first use. - -Tue Dec 16 12:59:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c: Collapse two identical declarations for join_file. - -Mon Dec 15 16:01:49 1997 Ian Lance Taylor <ian@cygnus.com> - - * client.c (start_tcp_server): Remove calls to htons and add one - call to ntohs (init_sockaddr calls htons on the port argument). - -Mon Dec 15 00:07:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (failure_exit): New variable. - (get_server_responses): If it is set, then return - failure. - (updated_seen, updated_fname): New variables. - (update_entries): Use updated_fname if set. In the "move away - foo.c; it is in the way" case print "C" not "U", and set - failure_exit. - (handle_mt): If we get +updated tagged text, stash it away in - updated_fname rather than printing it immediately. - (handle_mt, get_server_responses): If we stashed a filename and - didn't get around to printing it, go ahead and print it. - * sanity.sh (conflicts2-142d2): Adjust to test for fix. Remote is - now like local was in terms of exit status and "C aa.c" message. - -Sun Dec 14 00:27:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - Implement tagged text feature: - * update.c (write_letter): Take a single finfo argument rather - than file and update_dir. While we are at it change it to return - void (since the returned value always had been 0). - * update.c: Update callers. - * server.c, cvs.h (cvs_output_tagged): New function. - * client.c (responses): Add "MT" response. - (handle_mt): New function. - * update.c (write_letter): Output via cvs_output_tagged. - -Sun Dec 14 14:13:05 1997 Ian Lance Taylor <ian@cygnus.com> - - * recurse.c (do_dir_proc): Only check for CVS/Repository if - W_LOCAL. - * sanity.sh (devcom-t2, devcom-t3): New tests for above patch. - -Sun Dec 14 00:27:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * root.c (parse_cvsroot): Initialize check_hostname (fixes thinko - in GSSAPI changes). - -Sat Dec 13 13:15:35 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c: Use indentation to indicate nesting of #ifdef's. - - * client.c (connect_to_gserver): Reindent (in one place). - -Fri Dec 12 17:38:15 1997 Chris Provenzano <proven@cygnus.com> - and Ian Lance Taylor <ian@cygnus.com> - - * cvs.h (CVSmethod): Add gserver_method. - * root.c (method_names): Add gserver. - (parse_cvsroot): Handle :gserver:. - * client.h (cvsauthenticate): Declare. - (cvs_gssapi_encrypt): Declare if HAVE_GSSAPI and ENCRYPTION. - (cvs_gssapi_wrap_buffer_initialize): Declare if HAVE_GSSAPI. - (connect_to_pserver): Update declaration. - (pserver_authenticate_connection): Declare when HAVE_GSSAPI and - SERVER_SUPPORT is defined in addition to other case. - * client.c: If HAVE_GSSAPI, include GSSAPI header files. - (gcontext): New static variable if HAVE_GSSAPI. - (connect_to_pserver): Add do_gssapi parameter. Change all - callers. Move rejection handling to bottom of function. - (recv_bytes): New static function if HAVE_GSSAPI. - (connect_to_gserver): Likewise. - (start_server): Handle gserver_method. Handle GSSAPI encryption - and authentication. - * server.c: Include <sys/socket.h> if HAVE_GSSAPI, in addition to - existing cases. If HAVE_GSSAPI, include GSSAPI header files. - Include <grp.h> even if AUTH_SERVER_SUPPORT is not defined. - (gcontext, cvs_gssapi_wrapping): New static variables if - HAVE_GSSAPI. - (cvs_gssapi_encrypt): New global variable if HAVE_GSSAPI and - ENCRYPTION. - (serve_gssapi_encrypt): New static function if HAVE_GSSAPI and - ENCRYPTION. - (serve_gssapi_authenticate): New static function if HAVE_GSSAPI. - (requests): Add Gssapi-encrypt if HAVE_GSSAPI and ENCRYPTION. Add - Gssapi-authenticate if HAVE_GSSAPI. - (switch_to_user): Compile if HAVE_GSSAPI, in addition to existing - cases. - (pserver_authenticate_connection): Likewise. Ifdef out part of - the code for AUTH_SERVER_SUPPORT. Handle a GSSAPI request. - (gserver_authenticate_connection): New static function if - HAVE_GSSAPI. - (cvsauthenticate): New global variable. - (struct cvs_gssapi_wrap_data): Define if HAVE_GSSAPI. - (cvs_gssapi_wrap_buffer_initialize): New function if HAVE_GSSAPI. - (cvs_gssapi_wrap_input): New static function if HAVE_GSSAPI. - (cvs_gssapi_wrap_output): Likewise. - * main.c (opt_usage): Mention -a. - (main): Handle -a. Handle pserver if HAVE_GSSAPI, in addition to - existing cases. - * login.c (login): Pass new argument to connect_to_pserver. - -Fri Dec 12 15:33:19 1997 Ian Lance Taylor <ian@cygnus.com> - - * buffer.c (PACKET_SLOP): Define. - (packetizing_buffer_initialize): Use PACKET_SLOP when allocating - holdbuf. - (packetizing_buffer_input): Allow up to PACKET_SLOP bytes in - stackoutbuf. - (packetizing_buffer_output): Use just BUFFER_DATA_SIZE + 2 for - inbuf. Allow PACKET_SLOP + 4 extra bytes in stack_outbuf. - Correct >= to > in test of incoming number of bytes. Use - PACKET_SLOP in other tests. - -Fri Dec 12 10:27:08 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (start_tcp_server): Revise comment to reflect - SOCK_STRERROR and SOCK_ERRNO now being in use. - -Thu Dec 11 15:32:31 1997 Ian Lance Taylor <ian@cygnus.com> - - * client.c (init_sockaddr): Compile if HAVE_KERBEROS, as well as - if AUTH_CLIENT_SUPPORT. Return a pointer to a struct hostent. - (start_tcp_server): Clean up. Use init_sockaddr. Use - SOCK_STRERROR and SOCK_ERRNO. Don't bind the socket. - - Generalize buffering code used by Kerberos encryption routines - into a generic packetizing buffer. The new code in buffer.c is a - modified version of the code removed from server.c. - * buffer.c (struct packetizing_buffer): Define. - (packetizing_buffer_initialize): New function. - (packetizing_buffer_input): New static function. - (packetizing_buffer_output): New static function. - (packetizing_buffer_flush): New static function. - (packetizing_buffer_block): New static function. - (packetizing_buffer_shutdown): New static function. - * buffer.h (packetizing_buffer_initialize): Declare. - * server.c (struct krb_encrypt_data): Rename from - krb_encrypt_buffer, and remove all fields not related to - encryption. - (krb_encrypt_buffer_initialize): Just call - packetizing_buffer_initialize. - (krb_encrypt_input): New static function. - (krb_encrypt_output): New static function. - (krb_encrypt_buffer_input): Remove. - (krb_encrypt_buffer_output): Remove. - (krb_encrypt_buffer_flush): Remove. - (krb_encrypt_buffer_block): Remove. - (krb_encrypt_buffer_shutdown): Remove. - -Wed Dec 10 15:39:44 1997 Ian Lance Taylor <ian@cygnus.com> - - * buffer.c (stdio_buffer_initialize): Correct formatting. - -Sun Dec 7 09:37:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basicb-0d0): New test, for checkout on existing - directory. - -Sat Dec 6 00:25:11 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (binwrap3): Clean up repository too. Clean up working - directory with "rm -r" not "rm -rf". - -Thu Dec 4 17:11:18 1997 Larry Jones <larry.jones@sdrc.com> - - * subr.c (check_numeric): Don't reference argv[1] when argc is 1 - (should be argv[0]). - - * sanity.sh: Fix lines that look like conflict markers but aren't - to prevent problems checking in. - (binwrap3): Remove local CVSROOT when done so that later - tests that expect to create it don't fail. - -Thu Dec 4 18:19:21 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h: Remove mempcpy definition. I think the polite way to - describe my feelings about mempcpy is something like "we don't - have agreement that it is a good idea". - * rcs.c (truncate_revnum): Don't call it. - * sanity.sh: Run multibranch2 test by default. - (multibranch2): Use ${TESTDIR} a few places. - (multibranch2-9): Accept "P file1" as well as "U file1". - - * sanity.sh: Don't add 1997 to the copyright notice. Add GPL - terms. Add discussion of copyright issues. - * rcs.c (truncate_revnum, truncate_revnum_in_place, - compare_truncated_revnums): Reindent. - -1997-12-04 Jim Meyering <meyering@na-net.ornl.gov> - - * subr.c (xstrdup): Use memcpy rather than strcpy. - (compare_revnums): Declare parameters to be `const'. - Remove unnecessary uses of xstrdup and corresponding frees. - (increment_revnum): Declare parameter to be `const'. - Use memcpy rather than strcpy. - (gca): Declare parameters to be `const'. - (check_numeric): Declare REV parameter to be `const'. - (file_has_markers): Declare parameter to be `const'. - (get_file): Declare `char*' parameters to be `const'. - * run.c (run_exec): Declare `char*' parameters to be `const'. - * cvs.h (mempcpy) [! HAVE_MEMPCPY]: Define it. - Add `const' to types in several prototypes. - - * rcs.c (truncate_revnum): New function. - (truncate_revnum_in_place): New function. - (compare_truncated_revnums): New function. - (max_rev): New function. - (RCS_addbranch): Make BRANCH parameter `const'. - Use the above functions rather than open-coding them. - When BRANCH is a revision number, insert it *in order* - in the sorted list of branch numbers, not at the end. - Add assertion that insertion succeeds. - * sanity.sh (multibranch2): Test for this. - (Copyright): Add 1997. - -Dec 1997 Karl Fogel <kfogel@floss.red-bean.com> - - * wrapper.c (wrap_name_has): loop as far as wrap_count + - wrap_temp_count, not wrap_count + wrap_saved_count, otherwise - some wrappers get skipped. - (wrap_matching_entry): same. - * sanity.sh (binwrap3): new test, for import with - CVSROOT/cvswrappers and .cvswrappers specifying -k 'b' options. - -1997-11-30 Jim Meyering <meyering@na-net.ornl.gov> - - * client.c (send_a_repository): Strip trailing slashes from the name - of the update directory. Otherwise, running `cvs update dir/' provokes - this failure `protocol error: illegal directory syntax in dir/' when - running in client/server mode. - - * hash.c (insert_before): New function derived from addnode. - (addnode): Simply return insert_before. - (addnode_at_front): Simply return insert_before. - * hash.h (insert_before): Add prototype. - - * server.c (dirswitch): Compute `strlen(dir)' once and save it, - rather than computing it four times. Also do s/illegal/invalid/ to - this diagnostic: "E protocol error: illegal directory syntax in %s". - -Sun Nov 30 18:03:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * admin.c: Fix comment (no longer a front-end to "rcs"). - - * error.c, error.h (rcserror): Remove. - * admin.c, rcs.c: Call error instead of rcserror. This changes - the format of these messages from "rcs: <path>: error" to "cvs - <command>: <path>: error". The former format wasn't quite what - RCS printed anyway (because RCS would sometimes print "ci", "co", - &c, not "rcs"), and preserving RCS's exact output probably is not - a good idea anyway (because it will make people think that the - error was caused by an external program). In two cases, I tidied - up the message in a more drastic fashion ("cannot stat" in - RCS_checkin and "could not diff" in RCS_delete_revs). - - * sanity.sh (basica-o2b, binfiles2-o1, admin-18, admin-22-o10, - admin-22-o17): Look for "cvs <command>" not "rcs". - - * run.c, cvs.h (run_setup): Replace varargs nonsense with a single - argument which gets parsed as the result of the vasprintf - used to. - * client.c, commit.c, logmsg.c, modules.c, rtag.c, tag.c, update.c, - wrapper.c: Update callers, either to do the sprintf themself or to - just call run_arg if it will do the job. - * rcscmds.c: Likewise for call_diff_setup and callers. - - * run.c, cvs.h (run_args): Remove; nowhere used. - -Sat Nov 29 22:15:06 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * options.h.in: Remove declaration of getwd; see lib/ChangeLog for - rationale. - -1997-11-29 Jim Meyering <meyering@na-net.ornl.gov> - - * update.c (checkout_file): Initialize `backup'. - - * diff.c (diff_fileproc): Initialize `tmp' and `fname'. - - * modules.c (do_module): Initialize `server_dir_to_restore'. - (do_module): Initialize `value' in an else clause. - - * rcs.c (RCS_checkin): Initialize `commitpt'. - (RCS_delete_revs): Initialize `revp'. - (RCS_copydeltas): Always initialize `insertbefore'. - - * run.c (run_print): Define `outfn' even in error case. - -Mon Nov 24 17:28:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_findlock_or_tip): Prototype. - (RCS_checkin): Fix call to pass correct number of arguments. - -Sun Nov 23 10:34:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * recurse.c (do_dir_proc): Move check for CVS/Repository and - CVS/Entries to before where we call the direntproc. - * client.c (send_dirent_proc): Remove code to check for - CVS/Repository, now that recurse.c does it. - * sanity.sh (conflicts3-18 through conflicts3-19): New tests, for this. - -Sat Nov 22 10:54:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * recurse.c (do_dir_proc): Check that CVS/Repository and - CVS/Entries exist. - * sanity.sh (conflicts3-14 through conflicts3-17): New tests, for this. - - * client.c (send_fileproc): Send options field from - vers->entdata->options not vers->options. - * cvs.h (struct entnode): Add comment (options and timestamp must - not be NULL). - * sanity.sh (binfiles-9 through binfiles-13, binfiles-sticky5, - keyword-17): Remove kludges for remote; tests for fix. - - * update.c (update_fileproc): Fix comment; direct checkout is - still faster than patches for local but not for quite the - same reasons. - - * add.c (add): Pass SEND_NO_CONTENTS to send_files. - -Wed Nov 19 18:25:03 1997 Mike Glendinning <mikeg@sequent.com> - - * update.c (patch_file_write): Missing cast provided. - -Wed Nov 19 15:57:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_deltas): Solve trigraph problem (once and for all, I - hope) with 3 calls to cvs_output. - -Wed Nov 19 01:52:57 1997 Andy Piper <andyp@parallax.co.uk> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * classify.c (Classify_File), cvs.h (struct vers_ts), vers_ts.c - (Version_TS): Clarify NULL versus "" for options in comments. - * vers_ts.c (Version_TS): Treat "" the same way as NULL in options - and vers_ts->options. - * sanity.sh: New tests binfiles-sticky5 through binfiles-17 test - for this. - -1997-11-16 Karl Fogel <kfogel@floss.red-bean.com> - - * client.c (update_entries): parse server-sent entries line even - in the case of "cvs export", because we need to know if -kb option - is set. - Init `options' to NULL like anything else. - -Tue Nov 18 09:20:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version number to 1.9.21. - - * Version 1.9.20. - -Mon Nov 17 14:35:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (server_updated): If scratched_file and noexec are set, - clean up so we don't get a "duplicate Scratch_Entry" warning - later. - * sanity.sh: New tests conflicts3-10 to conflicts3-13, for this. - - * sanity.sh (conflicts3): Don't allow "file1 was lost" messages - here; I don't think CVS actually produced them, and they don't - belong. - -Sun Nov 16 23:19:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Accept either "U file1" or "P file1". - -Fri Nov 14 12:32:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c: Add comment about cleaning up ,foo, file on ^C. - -Fri Nov 14 11:56:29 1997 Andy Piper <andyp@parallax.co.uk> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * filesubr.c (unlink_file_dir): Don't print trace message in the - server. - -Fri Nov 14 11:28:55 1997 Jim Meyering and Jim Kingdon - - * rcs.c (RCS_getdatebranch): If the branch we are looking for - doesn't exist, return a revision which matches the date, not - just NULL. - * sanity.sh (tagdate): New test, for this. - -Thu Nov 13 10:11:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basicb-21): Fix comment which described a behavior - which no longer exists. - -Wed Nov 12 16:24:45 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - Clean up infrastructure made unnecessary by RCS library: - * rcscmds.c (diff_exec, diff_execv): Use literal "diff" not DIFF. - * options.h.in (DIFF), rcs.h (RCS, RCS_CI, RCS_DIFF, - RCS_RCSMERGE): Removed; no longer used. - * commit.c (commit), patch.c (patch_fileproc), - rcscmds.c (RCS_exec_rcsdiff), start of rcscmds.c: Update comments - to reflect librarification of RCS. - * options.h.in (RCSBIN_DFLT): Removed. - * main.c, cvs.h (Rcsbin, free_Rcsbin): Removed. - * main.c (main): Don't check RCSBIN environment variable. -b - global option is now a noop. - * cvs.h (RCSBIN_ENV): Removed. - * expand_path.c (expand_variable): $RCSBIN is now an error. - * mkmodules.c (config_contents): Remove RCSBIN. - * parseinfo.c (parse_config): RCSBIN now a noop. - * server.c (server): Don't put Rcsbin in PATH. - -Mon, 10 Nov 1997 Jim Kingdon - - * rcs.c (RCS_checkin): Actually, when we get a change text - for a text file using get_file, we want text mode, although - the reasons are kind of subtle (see comment). - - * rcs.c (RCS_checkin): Pass correct mode to get_file for - binary files. - - * rcscmds.c: Declare vasprintf. - -Mon Nov 10 11:11:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - This fixes problems with windows-NT/run.c improperly quoting, and - is cleaner anyway. - * rcscmds.c (call_diff_setup, call_diff_arg, call_diff_add_arg, - call_diff_argv, call_diff_argc, call_diff_argc_allocated): New - functions/variables, lightly adapted from src/run.c. - * cvs.h, run.c (call_diff, call_diff3): Move from here... - * rcscmds.c: ...to here. - -Sun, 9 Nov 1997 Jim Kingdon - - * rcs.c (rcs_internal_unlockfile): Call rename_file not rename. - This makes it work on NT again. - -Sun Nov 9 16:54:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (diffmerge2): Protect keywords against unwanted - expansion. They got clobbered and the testcase stopped working - when I checked it in. - -Fri Nov 7 13:23:38 1997 Karl Fogel <kfogel@floss.red-bean.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (diffmerge1, diffmerge2): new tests, for bugs, or - potential bugs, in ../diff/analyze.c which were fixed by Paul - Eggert's patch. - -Sun Nov 9 10:28:43 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_settag): Reindent. - - * rcs.c (rcs_internal_lockfile): Fix typo (thow -> throw). - -Sat Nov 8 15:58:53 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (cvsadm): Remove most of the tests which tested - CVS/Root. This takes the run time for the cvsadm tests from - about 5 minutes 15 seconds to about 4 minutes 10 seconds with no - significant loss in coverage. - - * rcs.c (rcs_internal_lockfile): Check for errors from system - calls. If open() gives an error, don't muck with stat and errno - (I don't know what the RCS code that this comes from was trying to - do, but it clearly isn't accomplishing anything here). - (RCS_rewrite, RCS_delete_revs): Check for errors from system calls. - -Sat Nov 1 14:21:29 1997 Michael L.H. Brouwer <michael@thi.nl> - - * rcs.c (RCS_checkin): Change type of bufsize from int to size_t. - (RCS_delete_revs): Change type of bufsize and len from int to size_t. - (RCS_getdeltatext): Change type of textlen from int to size_t. - * rcs.h (struct deltatext): Change len from int to size_t to keep - the compiler happy on systems where size_t is unsigned int. - [This goes well beyond keeping the compiler happy; if sizeof - (size_t) != sizeof (int), the old code was quite broken -kingdon] - -Sat Nov 1 14:21:29 1997 Michael L.H. Brouwer <michael@thi.nl> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_checkin): When checking if we were holding the lock - use delta->author instead of user since the latter might have been - clobbered by a call to getcaller. This resulted in the failure of - test basica-7. - [I don't completely follow the scenario where it gets clobbered, - it but sounds vaguely plausible and the replacement seems - cleaner, precisely because it avoids allocation issues -kingdon] - -Wed Nov 5 20:16:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * checkin.c, checkout.c, commit.c, cvs.h, import.c, login.c, - main.c, update.c: Change FALSE to 0 and TRUE to 1 and replace - monstrosities like "cvswrite == TRUE" with just "cvswrite". FALSE - and TRUE sometimes conflicted with system headers (NextStep3.3?), - but more to the point, good old 1 and 0 are fine and were used by - most of CVS already. - -Tue Nov 4 12:19:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_checkin, RCS_lock, RCS_unlock): Rename local variable - quiet to checkin_quiet or some such, to avoid confusion with - global variable quiet. - - * lock.c: Update comment to refer to add_rcs_file rather than "rcs - -i". - - * rcs.h (struct rcsnode): Add comments for all fields. - * rcs.c (RCS_delete_revs): Refuse to delete revisions which have - symbolic names. Fix fencepost bug which caused us to sometimes - check one more revision than we should for locks, branches, and - this. - (findtag): New function, to help above code. - - * admin.c (admin): Take out writelocks not readlocks. This has - been a bug "forever", but may become more noticeable with - rcs_internal_lockfile relying on the writelocks. - -Mon Nov 3 10:17:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_rewrite): Don't write the file if noexec. - * sanity.sh (basica, branches): Test for this. - -Sat Nov 1 10:01:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.h (struct deltatext): Comment text and log fields. - - * admin.c (admin_fileproc): Call RCS_reparsercsfile not - RCS_fully_parse. Don't muck with ->other field in RCSVers (it - doesn't need to be set). - * rcs.h, rcs.c (RCS_reparsercsfile): No longer static. No point - in having this static when RCS_rewrite and RCS_fully_parse are not. - * rcs.c (getdelta): Remove obsolete comment about not storing the - newphrases from the deltas, since we now do. - -Sat Nov 1 10:01:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - and Paul Eggert - - * rcs.c (rcs_internal_lockfile): Clarify the comments about O_EXCL - and such matters. - -Sat Nov 1 10:01:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_delete_revs): Pass force_tag_match to RCS_settag. - * sanity.sh (basica-o2a, basica-o2b): Test for this. - -1997-11-01 Peter Brandstrom <d91-pbr@nada.kth.se> - - * sanity.sh: Use ${username} more places. - -Sat Nov 1 00:14:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (rcs_internal_lockfile): Add comments about what we are - trying to accomplish here (versus what RCS tries to accomplish). - - * rcs.c (RCS_parsercsfile_i): Clarify/expand comment about - the purpose of having both this and RCS_reparsercsfile. - (RCS_rewrite): Add comment about how this works. - - * admin.c (admin_fileproc): Add comment about call to - RCS_fully_parse not RCS_reparsercsfile. - * rcs.h: Comment on what delta_pos field of struct rcsnode is. - -Fri Oct 31 16:38:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - and Abe Feldman - - * client.c (update_entries): If UTIME_EXPECTS_WRITABLE, if - necessary change the file to be writable temporarily to set its - modification time. - -Thu Oct 30 17:42:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * admin.c (admin): Deal with new :: syntax for ranges. - * rcs.c, rcs.h (RCS_delete_revs): New arg inclusive (set for the old - behavior, clear to enable new code). - * admin.c (admin_fileproc): Set it if :, clear it if ::. - * sanity.sh (basica, head, branches, log): Add tests for this feature. - - * admin.c (admin_fileproc): Clean up the error message which - happens if one of the RCS_* functions returns an error status; it - is confusing to say that "rcs" failed now that this is implemented - internally. - * sanity.sh (admin): Update accordingly. - -Wed Oct 29 07:07:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (admin-22-o24): New test, tests that admin -o - correctly munged the deltatexts on a branch too. - - * rcs.c (RCS_delete_revs): If we are deleting an entire branch, - delete the node in ->branches rather than setting the ->key to the - bogus value NULL. - * rcs.c (RCS_delete_revs): If "rev1" equals "branchpoint", then set - "before" to the revision on the trunk that we branch from. - * rcs.c (RCS_delete_revs): Don't set rev2 to revp->version (the - code is missing an xstrdup, but it doesn't matter because rev2 - isn't used after this point). - * sanity.sh (binfiles2-o2 to binfiles2-o4): New tests, for this. - -Tue Oct 28 19:30:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_delete_revs): Restore code which passes rev2 to - RCS_getbranchpoint if rev1 is NULL; it still makes sense for the - non-trunk case. Fixes admin-22-o22 in testsuite. - - * sanity.sh (admin-18): Adjust to reflect "rcs failed" no longer - being suppressed by global -q option. - - * rcs.c (RCS_delete_revs): If rev1 == NULL and rev2 is on the - trunk, handle it the same way we do everything else--by swapping - the two. This replaces the code which tried to kludge what we - passed to RCS_getbranchpoint (which didn't work). - * sanity.sh (binfiles2-o1 to binfiles2-o4): New tests, for this fix. - * admin.c (admin_fileproc): Don't have -q global option suppress - "rcs failed" message. - -1997-10-28 Jim Kingdon - - * log.c (printlock_proc), rcs.c (putlock_proc): Prototype. - * rcs.c (rcs_internal_lockfile): Only try to call fchmod if - HAVE_FCHMOD is defined. - -Tue Oct 28 10:27:03 1997 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_deltas): Don't use \? in string if __STDC__ is not - defined. - - * rcs.c (make_file_label): Remove extraneous `+'. - -Mon Oct 27 14:40:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * status.c (status): Don't pass SEND_NO_CONTENTS to send_files. - -Sat Oct 25 00:33:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_delete_revs): Use : not - for range in error message. - - * rcs.h: Add comment about '\0' in RCS fields. - - * rcs.c (getdelta): Add comment about branches and next field - being mandatory. - - * rcs.c (RCS_reparsercsfile, RCS_deltas), sanity.sh (reserved): - Reindent sections which were misindented as a result of recent - changes. - -Fri Oct 24 10:22:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_findlock_or_tip): Don't worry about file ownership - and nonstrict locking when returning the default branch or head. - The most conspicuous problem with the old code is that in the - error case it would examine rstat.st_uid when it had not been - set. For a discussion of more fundamental reasons, see comment. - - * admin.c (admin_fileproc): In handling -A, don't handle relative - pathnames differently from absolute pathnames. See comment for - rationale. If problem opening the file, give a nice error not a - coredump. - * sanity.sh (admin-19a-admin, admin-19a-log, admin-19a-fix): - New tests, test for traditional "cvs admin -A" behavior with - relative pathnames. - * sanity.sh (admin-19a-nonexist): Test for the core dump fix. - * sanity.sh (admin-22-o1): Look for ${PROG} not cvs. - - * sanity.sh (reserved-16): Remove commitinfo change with "cvs - commit" not "cvs admin -o". In addition to commit being The Right - Thing on general principles, cvs admin -o doesn't work because it - doesn't rebuild the administrative file database. - - * update.c (patch_file): If the first revision does not exist in - the RCS file, fall back to sending entire file. Fixes - admin-22-o15 in make remotecheck. - -1997-10-23 enami tsugutomo <enami@but-b.or.jp> - - * rcs.c (RCS_checkin): Unlink temporary files stored in variable - `tmpfile' and `changefile'. - -Wed Oct 22 12:16:10 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (rcs_lockfilename): Allocate enough memory for terminating - '\0'. - - * admin.c (admin_fileproc): Don't support '-' for ranges in "cvs - admin -o". - (admin): Adjust comment. - - * rcs.h (RCSVers): New field other_delta. - * rcs.c (free_rcsvers_contents): Also free other_delta. - (getdelta): Read newphrases from deltas into other_delta field. - (putdelta): Write those newphrases. - * sanity.sh (rcs-8a): New test, for this fix. - * admin.c (admin_fileproc): If "-b" without argument, then set - branch to NULL, not "" (uncovered by rcs-8a test). - * rcs.c (putrcsfield_proc): Add comment about how we (mis)handle - values in newphrases. - - * sanity.sh (reserved): Instead of looking for rcslock.pl in CVS - distribution, just use our own equivalent. - - * rcs.c (RCS_rewrite): Call ferror before fclose to avoid "Invalid - argument" warnings. - -Mon Oct 20 00:30:16 1997 Tim Pierce <twp@twp.tezcat.com> - - [I removed a ChangeLog entry for a change to sanity.sh (editor), - because the actual change was not made. With this change, CVS no - longer runs RCS. I'll be checking in my cleanups shortly. -kingdon] - - Librarify `ci'. - * rcscmds.c, cvs.h (RCS_checkin): Removed. - * rcs.c, rcs.h (RCS_checkin, RCS_getbranchpoint, RCS_addbranch, - RCS_findlock_or_tip): New functions. RCS_checkin completely - rewritten to eliminate RCS 5.7; change `rcs' parameter from string - to RCSNode, so we can update RCSNode without re-reading from - disk. - * checkin.c (Checkin): Updated RCS_checkin caller, moved RCS_parse - call to before RCS_checkin. - * import.c (add_rev): Updated caller. - * commit.c (remove_file): Updated caller. - (checkaddfile): Updated caller. Parse `rcsfile' after - calling add_rcs_file. Free `rcsfile' instead of asserting it to - be NULL. - - Librarify `rcs'. - * rcscmds.c, cvs.h (RCS_exec_settag, RCS_exec_deltag, - RCS_exec_setbranch, RCS_exec_lock, RCS_exec_unlock): Removed. - - * rcs.c (RCS_settag): Rewritten to eliminate RCS 5.7. - * commit.c (checkaddfile): Call RCS_rewrite after calling RCS_settag. - * import.c (add_tags): Same. - * rtag.c (rtag_fileproc): Same. - * tag.c (tag_fileproc): Same. - - * rcs.c (RCS_deltag): Rewritten to eliminate RCS 5.7. Remove - `quiet' parameter, since this function no longer prints any output. - * commit.c (remove_file): Update caller. Also call RCS_rewrite - after RCS_deltag. - * rtag.c (rtag_delete): Same. - * tag.c (tag_fileproc): Same. - - * rcs.c (RCS_setbranch): Rewritten to eliminate RCS 5.7. - * commit.c (remove_file): Call RCS_rewrite after calling RCS_setbranch. - (fixbranch): Same. - (lock_RCS): Same. - - * rcs.c (RCS_lock): Rewritten to eliminate RCS 5.7. Change third - arg to mean `quiet' and not `noerr', permitting admin_fileproc to - run RCS_lock verbosely. - * commit.c (lock_RCS): Update callers; call - RCS_rewrite after RCS_lock. - (remove_file): Same. Call RCS_lock quietly. - * import.c (add_rev): Same. Do not print `fork failed' error - message, since we're no longer forking. - - * rcs.c (RCS_unlock): Rewritten to eliminate RCS 5.7. Change - `noerr' arg to mean `quiet', permitting admin_fileproc to run - RCS_unlock verbosely. Use notify_do when breaking another user's - lock. Include "edit.h" for notify_do prototype. - * checkin.c (Checkin): Update caller; use RCS_rewrite after RCS_unlock. - * commit.c (unlockrcs): Same. - * import.c (add_rev): Same. - - * rcs.c, rcs.h (RCS_getlocks, RCS_addaccess, RCS_delaccess, - RCS_getaccess, RCS_delete_revs): New functions. - (expand_keywords, RCS_lock, RCS_unlock): Use RCS_getlocks. - * log.c (log_fileproc, log_version): Call RCS_getlocks. Don't add - bogus ";locker" nodes to RCSVers nodes -- walk lock list with - printlock_proc. - (printlock_proc): New function. - - * admin.c (admin_fileproc): Largely rewritten: call internal RCS - library functions instead of forking RCS processes. - (admin, admin_fileproc): Obsolete -V option. - (struct admin_data): Remove `version' member. - * sanity.sh (admin-24): Remove -V test case. - - New functions for reading and writing RCS files. - * rcs.h (struct deltatext, Deltatext): New types. - (struct rcsversnode): New members `text' and `outdated'. - (struct rcsnode): New members `access', `locks', `strict_locks', - `comment', and `desc'. - * rcs.c (RCS_reparsercsfile, expand_keywords): Use new RCSNode members. - (free_rcsnode_contents): Free them. - * log.c (log_fileproc): Use new RCSNode members instead of ->other. - - * rcs.c (getdelta, RCS_getdeltatext, freedeltatext, do_locks, - RCS_putadmin, RCS_putdtree, RCS_putdesc, putdelta, - putrcsfield_proc, putsymbol_proc, RCS_copydeltas, putdeltatext, - RCS_rewrite, getrevnum, rcs_internal_lockfile, - rcs_internal_unlockfile, rcs_lockfilename): New functions. - - (RCS_reparsercsfile): Use getdelta, making sure fp is positioned - correctly before calling it. Skip `head' and `branch' nodes: we - have already parsed them, and they were being added incorrectly to - rcs->other. Do not signal error if the RCS file has an empty - delta tree; this made it impossible for RCS_checkin to perform an - initial checkin. Remove `all' parameter; always store all RCS - fields. - (RCS_fully_parse, RCS_gettag, RCS_getbranch, RCS_getdate, - RCS_getdatebranch, RCS_getrevtime, RCS_symbols, translate_symtag, - RCS_isdead, RCS_getexpand, RCS_checkout, annotate_fileproc): - Update all callers to remove `all' parameter. - - (getrcskey): Do not append trailing whitespace to a value. This - corrupted some log fields and wrecked some sanity.sh test cases. - - (free_rcsvers_contents): New function. - (rcsvers_delproc): Call it. - - * rcs.h (NODELTA): Removed symbol; now obsolete (since RCSNodes - do not go stale). - * import.c (add_rev): Removed NODELTA reference. - * rcs.c (RCS_reparsercsfile, RCS_checkout, RCS_settag, RCS_deltag, - RCS_setbranch, RCS_lock, RCS_unlock, RCS_deltas): Removed NODELTA - references. - - Miscellaneous changes to support RCS librarification and fix some bugs. - * subr.c, cvs.h (line2argv): Add `sepchars' argument. - * modules.c (cat_module, admin_fileproc): Update all callers. - - * subr.c, cvs.h (compare_revnums, increment_revnum): New functions. - (make_message_rcslegal): Strip whitespace from end of - lines and end of string, a la `cleanlogmsg' in RCS 5.7. - (get_file): Terminate buf with \0, extending it if - necessary. Read from stdin if `name' arg is NULL. - * admin.c (admin_fileproc): Call get_file to read -t arg from stdin. - - * error.c, error.h (rcserror): New function, used everywhere. - - * hash.c, hash.h (addnode_at_front): New function. - * rcs.c (RCS_settag, RCS_lock): Call it. - - * import.c, cvs.h (expand_at_signs): Make extern. - * rcs.c (putrcsfield_proc, RCS_putadmin, RCS_putdesc, - putdeltatext): Call it. - - * rcs.c (make_file_label): Use last_component to get file's basename. - - * sanity.sh (srcdir): New variable. - (rcs-7): Remove newphrase warning, no longer produced by CVS. - (rcs-8): Permit random whitespace around newphrase fields. - (admin-22): New test cases for -o options: admin-22-o{1..23}. - (reserved): New test cases for rcslock.pl: reserved-{8..16}. - -Tue Oct 21 16:48:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * tag.c (tag_check_valid): Add comment about locking or lack - thereof. - -1997-10-20 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version number to 1.9.19. - -1997-10-19 Jim Kingdon - - * Version 1.9.18. - -Wed Oct 15 15:21:43 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (username): Add '-' to characters allowed in user name. - - * rcscmds.c (diff_exec): Remove item about external diff - programs. It doesn't really belong here now that diff is - librarified and TODO #191 now mentions this. - - * checkout.c (checkout_proc): Add comment about assuming '/' is - the only path separator. - * options.h.in: Fix thinko (CVS/Repository -> CVS/Root). - -Mon Oct 13 22:46:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (commit): Add comment about CVS_BADROOT and command - other than "commit". - -1997-10-11 Noel Cragg <noel@swish.red-bean.com> - - * options.h.in: RELATIVE_REPOS has been checked for bitrot -- it - now works again. Change the comment before the #define to say - that we'll be switching to it soon. - - * sanity.sh (basicb-1, basicb-1a): update dotest strings to match - no matter if we're running with RELATIVE_REPOS defined or not. - (basicb-9b, basicb-9c): same. - - * sanity.sh (basicb-9b, basicb-9c): modified tests, since the - checkout.c fix changes the way this test module is checked out. - (basicb-9d, basicb-9e, basicb-9f): new tests, same. - (basicb-18): modify test, same. - (cvsadm): new set of exhaustive tests to check the contents of - CVS/Root and CVS/Repository files under various conditions. As a - side effect, it tests the behavior of the "-d" flags (command line - and modules file). - (modules3-7e through modules3-7h): removed, since these tests were - a small subset of what is tested in the new cvsadm section. - (modules-1b, modules-1c): same. - (modules-2b, modules-2c): same. - (modules-3b, modules-3c, modules-3e, modules-3f): same. - - * create_adm.c (Create_Admin): be a bit more verbose when using - trace mode. - - * checkout.c (checkout_proc): rewrote the code that sets the where - variable and the code that matches directory names with repository - directories. This fixes a long-standing bug in CVS. (It used to - be the case that "cvs co -d foo <mod1> <mod2>" would not properly, - where <mod1> and <mod2> where defined in the modules file. While - the first module would be checked out correctly, the second would - be checked out under the name of the directory to which the module - referred rather than the module name!). This fix also allows us - to check out things into directories that are more than one deep - (e.g. "cvs -d foo/bar/baz co blah" will now work). - (checkout): remove code that performed a CHDIR if the - number of arguments specified was greater than one, since it's no - longer necessary. Also remove the code that prevented us from - doing "cvs co -d <dir1>/<dir2>" without <dir1> existing, since - checkout_proc handles things correctly now. - - * cvs.h: fix typo. - - * rtag.c (rtag): reformat so that we don't run over 80 characters - per line. - (rtag_dirproc): same. - - * sanity.sh: change all old test cases to use pass and fail - functions rather than doing some combination of echo and exit - themselves. - - * commit.c (commit_direntproc): remove the "warm fuzzy" -- this - code never gets called when running in client/server mode, and we - should have CVS' output match as much as possible between the two - modes. Moreover, there is no analogous place to put this same - message when we're running in c/s mode. - (find_direntproc): print the same "fuzzy" as in check_direntproc - so that local and c/s mode have the same messages. - * sanity.sh (187a3): update test case to reflect the above. - -Thu Oct 9 10:57:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * parseinfo.c (parse_config): Add comment about compatibility - issues with adding keywords. - -Wed Oct 8 16:40:37 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * recurse.c (do_dir_proc), commit.c (check_direntproc, - commit_direntproc, find_dirent_proc): If this - directory doesn't exist, skip it. - * diff.c (diff_dirproc): Reindent. - * sanity.sh (deep-4b0a, deep-4b0b): Check for this fix. - -Thu Sep 26 16:30:00 1997 Larry Jones <larry.jones@sdrc.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (checkout_file): Don't set timestamp in noexec mode. - * vers_ts.c (Version_TS): Add comment about ignoring errors from - utime. - * sanity.sh (conflicts3): New tests, for this fix. - -Fri Oct 3 09:47:04 1997 Noel Cragg <noel@swish.red-bean.com> - - * sanity.sh (168): use PROG instead of CVSBASE, since they are - equal. - (importb-2): refer to PROG instead of "cvs" in error message. - - * add.c (add): use PROGRAM_NAME in the error message rather than - "cvs". - * classify.c (Classify_File): same. - * commit.c (find_fileproc): same. - * sanity.sh: change all add notification messages to refer to PROG - rather than "cvs". Fixed nasty quoting in several places at the - same time, replacing older "'command'" forms with newer - ".command." for simplicity. - -Sat Sep 27 01:37:10 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (rcslib-merge-8): Accept "P file1" as well as "U file1". - -Fri Sep 26 22:24:10 1997 Noel Cragg <noel@swish.red-bean.com> - - * create_adm.c (Create_Admin): assign our duplicate pointer `cp' - after the xrealloc of `reposcopy' because the latter might have - changed addresses. - -Fri Sep 26 14:25:59 1997 Tim Pierce <twp@twp.tezcat.com> - - * run.c (call_diff): Don't reset optind; this is done by diff_run now. - - Librarify rcsmerge/diff3. - * rcscmds.c, cvs.h (RCS_merge): Rewritten from scratch: check out - selected files and diff3 them. Take new `rcs' and `workfile' - arguments, so we can resolve symbolic tags and manipulate the - working file. - * update.c (merge_file, join_file): Update RCS_merge calls. - * run.c, cvs.h (call_diff3): New function. - - * sanity.sh (rcslib): New tests, rcslib-merge-{1..13}. - -Fri Sep 26 22:59:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * create_adm.c (Create_Admin): Fix thinko in Noel's change: keep - track of the originally allocated "cp" and free it, rather than - calling free on a pointer which may point halfway into the allocation. - * repos.c (Sanitize_Repository_Name): Per HACKING, assert that - repository != NULL, rather than just silently returning if NULL. - Reindent a line. - -Fri Sep 26 15:40:00 1997 Noel Cragg <noel@swish.red-bean.com> - - * sanity.sh (modules): add tests modules-[123]* that make sure the - administrative files get rebuilt in various cases. - - * add.c (combine_dir): removed function, since we no longer need - to worry about stripping the "." path element out. Changed the - two callers to simply concatenate their two arguments. - - * recurse.c (do_dir_proc): don't bother trying to strip off "." in - the repository name since the below changes fix that behavior -- - simply concatenate the repository and directory names together. - - * checkout.c (checkout_proc): sanitize the repository name after - constructing it (we may create "/path/to/repos/.", but we don't - want that to be passed around). Remove the code that tacks on - "/." when constructing top_repository, since the below changes fix - that behavior. Added comments to the part of this function that - builds administrative files. - - * sanity.sh (basicb): now that the below weirdness is fixed, the - extra "." path element in test basicb-0c doesn't appear when a - top-level file is checked out. Remove it from the expect string. - - * create_adm.c (Create_Admin): now that the repository name isn't - floating around with "." as the last path element, make creation - of the top-level administrative files a special case -- save the - repository name as "/path/to/repos/." Why? I considered not - including the "." but didn't know how it would affect the remote - protocol when RELATIVE_REPOS was defined (do we have a way of - sending "" via the protocol?). After I make sure that the - RELATIVE_REPOS patches still work, I'll check the "" possibility - so we don't have to have a this special case. - - * repos.c (Sanitize_Repository_Name): new function that removes - (if present) the trailing slash and "." component from the - repository name. Many routines break if we don't guarantee this. - See the comment before the function for complete information. - (Name_Repository): call Sanitize_Repository_Name before returning - the value. - * cvs.h: add prototype for Sanitize_Repository_Name. - -Fri Sep 26 14:19:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h (CVS_CMD_USES_WORK_DIR): Fix comment (the sense of the - flag is not reversed from what it would seem; when I thought so it - was because I was misreading the lookup_command_attribute code). - -Thu Sep 25 23:14:47 1997 Noel Cragg <noel@swish.red-bean.com> - - * parseinfo.c (Parse_Info): fix typo in the trace message. - -Thu Sep 25 14:22:54 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * build_src.com: Also link with diff.olb. - - * main.c (Make_Date): If gmtime returns NULL, try localtime. - -Wed Sep 24 19:18:40 1997 Noel Cragg <noel@swish.red-bean.com> - - * checkout.c (checkout): fix typo in comment. - -Wed Sep 24 08:31:46 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (patch_file): Revise comments about diff -a now that - diff is librarified. - -Sun Sep 21 21:28:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * run.c (call_diff): Sleep for a second, in hopes of helping with - out of order bugs. - -Sat Sep 20 07:19:18 1997 Tim Pierce <twp@twp.tezcat.com> - - Integrate diff library into CVS. - * run.c, cvs.h (call_diff): New function. - * rcscmds.c (diff_exec, diff_execv): Get diffs from call_diff - instead of running diff as a subprocess. - * Makefile.in (cvs): Add ../diff/libdiff.a. - - * diff.c (longopts, diff): Use 131 for --ifdef, fixing Jim's thinko - (using 147 for both --side-by-side and --ifdef). - - * sanity.sh (rcslib): Added tests rcslib-diffrgx-*, to test - handling of regex diff options. - -1997-09-21 Jim Kingdon <kingdon@harvey.cyclic.com> - - (Note that this requires that DIFF support -L. I'll be checking - in a fix to that in a moment, but I wanted separate checkins in - case that helps with clarity). - Tweaks to rcsdiff librarification: - * sanity.sh (rcslib): Change "cvs" to "${PROG}" and subcommand - names (e.g. "add") to "[a-z]*". Former should deal with ${testcvs} - being "cvs.old" or something; latter fixes make remotecheck. - * rcs.c (make_file_label): Take into account strlen (rev) when - allocating space. Removes a FIXME and probably fixes a buffer - overrun security hole. - * rcscmds.c (RCS_exec_rcsdiff): Remove #if 0'd code to call - rcsdiff. Tim says he has compared the new code with rcsdiff code - and is confident that the behavior is preserved, so we need to - nuke the comment which says this has not been done. #if 0 isn't - really a very good way to document the way it used to work anyway; - the old code is still in CVS. - * diff.c: Add comment about rcsdiff options that we don't support, - which Tim had sent in email. Remove -T and -y, as the - previous meaning had been very confused. - -1997-09-21 Tim Pierce <twp@xochi.tezcat.com> - - Librarify rcsdiff. - - * diff.c (have_rev1_label, have_rev2_label): New variables. - (diff): Generate file labels with make_file_label if necessary; - pass labels, revisions and working file name to RCS_exec_rcsdiff. - * rcscmds.c, cvs.h (RCS_exec_rcsdiff): Completely revised function - to eliminate rcsdiff dependency, based on patch from JimK. - (diff_execv): New function, to exec diff with explicit -L args. - * rcs.c, rcs.h (make_file_label): New function. - (RCS_output_diff_options): New function. - * sanity.sh (rcslib): New test. - -Fri Sep 19 15:08:08 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_nodeisbranch): Assert that RCS is non-NULL. - * commit.c (remove_file), rcs.c (RCS_getversion), rtag.c - (rtag_fileproc), status.c (status_fileproc, tag_list_proc), tag.c - (tag_fileproc): Call RCS_nodeisbranch not RCS_isbranch - in contexts where we know the RCS argument is non-NULL. - - * commit.c (find_fileproc): Pass tag not NULL to Version_TS for - the tag. - * vers_ts.c (Version_TS): Improve (somewhat) the introductory - comment. - * sanity.sh (editor): New test editor-9 tests for above fix. - Renumber/tweak surrounding tests to fit. - - * log.c (log_version): If p->data is NULL, it is an empty log - message. - * sanity.sh (rcs-14): New test, tests for above fix (previously - this was a coredump). - -Thu Sep 18 08:45:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (rcs-7): Fix stupid ${TESTDIR} omission. - -Wed Sep 17 16:27:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (rcs): New tests rcs-5 through rcs-13 test for - getdate.y fix (rcs-12 and rcs-13 both failed with the buggy - getdate.y). - -Tue Sep 16 00:07:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (editor): Clean up first-dir at end of test. - - * sanity.sh (editor): New tests test do_editor. - - * commit.c (commit): For the client, if we got the log message - from do_editor and there was an error, don't toss the message. - -Mon Sep 15 14:27:54 1997 martin.sjoelin@ubs.com - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (RCS_checkout): fwrite in bite-size pieces, not the whole - file in one fwrite. - -Sun Sep 14 12:23:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (check_fileproc): If the file has "conflict - indicators", spit a warning and proceed with the checkin. - * sanity.sh (conflicts): Adjust tests conflicts-132, - conflicts-status-3, conflicts-133, and conflicts-status-4 - for new behavior. - -Fri Sep 12 11:12:34 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c, admin.c, checkin.c, checkout.c, classify.c, commit.c, - create_adm.c, cvsrc.c, diff.c, entries.c, find_names.c, hash.c, - import.c, lock.c, log.c, logmsg.c, main.c, modules.c, myndbm.c, - no_diff.c, parseinfo.c, patch.c, rcs.c, rcscmds.c, recurse.c, - remove.c, repos.c, root.c, rtag.c, status.c, subr.c, tag.c, - update.c, vers_ts.c, hash.h, rcs.h, options.h.in: Change "CVS 1.4 - kit" to "CVS source distribution". - - * sanity.sh: Comment out call to "whoami". - -Thu Sep 11 10:09:04 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (classify_file_internal): Add comment about saving - quiet vs. saving really_quiet. - - * sanity.sh (newb-123j0): Use two regexps instead of assuming that - expr has "\(", "\|", and "\)". If we want to require the latter, - we should check for it up front, rather than let people get - halfway through and wonder why the test failed. - -Tue Sep 9 19:22:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * expand_path.c (expand_path): If GETPWNAM_MISSING is defined, - just give an error instead of calling getpwnam. - - * subr.c (getcaller): If SYSTEM_GETCALLER is defined, call it - instead of all the getlogin/getpwuid/etc. - * wrapper.c (wrap_setup): Call get_homedir not getpwuid. - -Mon Sep 8 17:54:14 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basicc): Change ls -1 to echo *; according to - larry.jones@sdrc.com, ls -1 isn't portable. - -Sun Sep 7 07:45:35 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basic2): In test basic2-64, match usernames with - ${username}. - - * root.c: Reindent a few things. - * root.c, cvs.h (same_directories): Remove. Never used, - portability hassle. - - * add.c (add_directory): When checking for CVSADM, call fncmp not - strcmp. I actually suspect this code doesn't do much these days, - but fncmp clearly will make more sense than strcmp. - - * rtag.c (rtag_usage), tag.c (tag_usage): Reword to hopefully be - clearer that -r takes either numeric or symbolic revision. - - * ignore.c (ign_dir_add, ignore_directory): Reindent. Tweaks to - comments. - - * update.c (checkout_file): Only ignore existence_error from - unlink_file_dir, not all errors. - - * checkout.c (safe_location): Check for errors from xgetwd. - * create_adm.c (Create_Admin): Remove call to xgetwd; it is just - debugging code anyway and it wasn't checking for errors. - - * sanity.sh: Add comment about default value for TESTDIR. - - * server.c (serve_log): Change "cvslog" to "log". This - (accidental, I presume) error had made it impossible for anonymous - users to run "cvs log". - - * classify.c (sticky_ck): Change to take an finfo argument rather - than several arguments taken from there. Cleans up the way the - calling convention had depended on SERVER_SUPPORT. - (Classify_File): Change callers. - - * version.c: Change version number to 1.9.17. - - * Version 1.9.16. - - * recurse.c (do_dir_proc): In combining repository and dir, omit - trailing "/." from repository. - * sanity.sh (modules3): Adjust test modules3-4 so we test for - this fix (this is not just cosmetic; the bug prevented the - "Rebuilding administrative file database" from happening). - modules2 already tests the "co CVSROOT/modules" usage. - - * checkout.c (checkout_proc): When building top-level CVSADM - directory, continue the process of walking up the repository one - more level, rather than putting in the same repository as for the - first-level directory. - * sanity.sh: Adjust tests basicb-1b, basicb-9b, modules3-7f, - toplevel-9, and toplevel-11 to test for this fix. - - (For reference, this takes CVS's text segment from 344460 to - 344140 bytes. I know, this may seem unimportant, but it is so - unusual for programs to shrink and I think it is so cool when they - do without losing functionality/clarity/etc). - * checkout.c, cvs.h (emptydir_name): New function. - * checkout.c (checkout, checkout_proc), modules.c (do_module): - Call it instead of duplicating the code to do that. - - * sanity.sh (basicc): Clean up first-dir at end of test. - -Sat Sep 6 09:48:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (join): Fix cut and paste error in join-28 - (/home/kingdon/... -> ${TESTDIR}). - - * recurse.c (start_recursion): If there is no CVSADM and no - subdirectories, give an error. - * sanity.sh (basicc): New tests, test for this fix. - - * sanity.sh (join): New tests join-25 through join-29 test merging - from one branch to a different branch. - - * release.c: In comment about CVSROOTADM_IGNORE, also mention - comment just added to entries.c. - * entries.c: Expand this comment, especially the part about - CVS/Template. - - Keep track of what revisions CVS/Base correspond to: - * cvs.h (CVSADM_BASEREV, CVSADM_BASEREVTMP): Added. - * entries.c, cvs.h (base_register, base_deregister, base_get, - base_walk): New functions. - * edit.c (edit_fileproc): Call base_register when setting up CVS/Base. - (unedit_fileproc): When taking a file out of CVS/Base, put its - revision back into entries, and base_deregister it. - * sanity.sh (watch4): New tests watch4-10 through watch4-18 test - for above fix. - -Fri Sep 5 09:14:10 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c: Only declare start_rsh_server if we are going to - define it (!NO_EXT_METHOD). - - * subr.c, cvs.h (check_numeric): New function. - * admin.c (admin): Call it. - * sanity.sh (admin): New tests admin-10a and admin-10b test for fix. - -Thu Sep 4 15:55:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (binwrap2): New tests, test for the ability to specify - all files are binary except certain patterns. - - * sanity.sh (modules3): New tests modules3-16 and modules3-17 test - for another behavior involving '/' in a module name. - -Sun Aug 31 12:03:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add): Remove checks for '/' in pathnames. - (add): Move code which handles entries and repository inside loop, - since these now might be different for each argument. Add code to - set finfo.update_dir, finfo.file, and finfo.fullname appropriately - even if pathname contains '/'. Replace user variable with - finfo.file or finfo.fullname, depending on which is meant. chdir - into update_dir for each argument. Likewise for the client code - which creates directories. - (add_directory): Replace arguments with a single finfo argument. - Replace dir with finfo->fullname as needed. - (add): Update call to add_directory. - * client.c, client.h (send_a_repository): No longer static. - * sanity.sh (errmsg2): Adjust tests to test for '/' in pathname. - - * sanity.sh (errmsg2): New tests errmsg2-13 through errmsg2-16 - test the status quo with respect to '/' in cvs add argument. - -Sat Aug 30 17:37:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * run.c (run_popen): Add comment on return value. - * release.c (release): Check for NULL return from popen. - -Fri Aug 29 17:49:20 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (get_server_responses): Add comment about "ok^M". - -Thu Aug 28 13:35:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * edit.c (edit_fileproc): If file doesn't exist, give an error. - * sanity.sh (devcom2): Tests devcom2-12 through devcom2-17 test - for above fix. - -Tue Aug 26 16:42:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * subr.c (xmalloc): Reword error message to clarify that memory, - not disk space or some other resource, is in question. - -Tue Aug 26 01:04:48 1997 Steve Ralston <sralston@ppdpost.ks.symbios.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add_directory): In allocating message, also allocate - enough for tag and date related text. - -Tue Aug 26 01:04:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (update_dirent_proc): Use update_dir not dir in "new - directory" message. - * find_names.c (find_dirs): Skip CVSNULLREPOS. - (Find_Directories): Add comment about find_dirs skipping CVSATTIC - and CVSLCK in working directories. - * sanity.sh (basicb): New tests basicb-edir-* test for find_dirs - fix. Change other tests to test that Emptydir is not special in - non-CVSNULLREPOS contexts. - -Sun Aug 17 14:44:57 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * import.c (add_rcs_file): Add comment about -k overriding wrappers. - -Sat Aug 16 18:09:05 1997 Martin Sjoelin <martin.sjoelin@ubs.ch> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * import.c (add_rcs_file): Before opening the input file - when importing, if options is binary, open the file in - binary mode. - -1997-08-16 enami tsugutomo <enami@ba2.so-net.or.jp> - - * sanity.sh (mcopy): Unset CVSWRAPPERS last of all. - -Fri Aug 15 11:11:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add_directory): Copy default file attributes from the - parent directory to the directory we are creating. - * fileattr.h, fileattr.c (fileattr_getall, fileattr_setall): - New functions, in support of above. - * fileattr.c (fileattr_free): Add comment about fileattr_write - maybe not clearing attrs_modified. - * sanity.sh (watch4): New test, tests for above fix. - -Thu Aug 14 11:08:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (merge_file, join_file): If wrap_merge_is_copy, treat - files as nonmergeable (as we had been treating binary files). - (join_file, update_fileproc): Remove previous wrap_merge_is_copy - cruft. - * sanity.sh (mcopy): New tests, test for above fix. - (binfiles2): New tests binfiles2-9a-* correct an oversight. - (binfiles, binfiles2): Adjust to reflect wording change from - "binary file" to "nonmergeable file". - (mwrap): Adjust tests mwrap-8 through mwrap-10 for new behavior. - - * main.c (main): Reword copyright notices to include the latest - year, to refer to "other authors" in addition to the ones listed, - and to be more concisely formatted. - -Wed Aug 13 13:50:00 1997 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh: Replace hard-coded directory with ${TESTDIR}, add - join3 to default tests - -Wed Aug 13 11:42:24 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcscmds.c: Adjust comment to reflect progress on removing RCS - execs outside this file. - -Mon Aug 11 10:14:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * vers_ts.c (Version_TS): If vers_ts->vn_rcs == NULL, skip setting - modification time in server case as well as local case. - * server.c (server_modtime): Add assertion to clarify that caller - must assure that vers_ts->vn_rcs != NULL. - * sanity.sh (join3): Add file "file2" to test for above fix. - - * modules.c (save_d): When parsing -s option, don't assume that - we will hit a space before we hit the '\0'. - (struct sortrec): Document allocation policies (status quo except - status field is now malloc'd). - (cat_module): No longer need to set the '\0' at the end of the - status field back to ' ', as it no longer shares storage with the - rest field. - * sanity.sh (modules): Add "statusmod" to test for above fix. - -Sun Aug 10 12:18:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Remove TODO item about more keyword expansion tests. - The keyword test and others cover it pretty well, and such an item - isn't useful unless it is specific. - - * sanity.sh (importb): New tests test "cvs import -b". - - * mkmodules.c: Update comment with more reasons why having - CVSROOT/passwd be a regular administrative file would be a Bad - Idea. - - * server.c (switch_to_user): Add comment about checking for errors - from setuid and friends. - -Wed Aug 6 13:48:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): Add comment about errors writing CVS/Root in - need_to_create_root code. - -Tue Aug 5 22:05:20 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * entries.c (write_entries): If trouble writing Entries.Backup, - make it a warning not an error. - -Wed Jul 30 08:42:04 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * parseinfo.c (parse_config): If AUTH_SERVER_SUPPORT is not - defined, don't set system_auth. - - * version.c: Change version number to 1.9.15. - - * Version 1.9.14. - - * create_adm.c, cvs.h (Create_Admin): If new argument WARN is set, - then make creating the CVS directory itself a warning not a fatal - error. New return value indicates whether we did this. - * checkout.c (build_one_dir), client.c (call_in_directory): - Pass WARN as one. - * add.c, client.c, checkout.c, modules.c, update.c: Pass WARN as - zero for all other Create_Admin callers. - * sanity.sh (toplevel): New test toplevel-12 tests for this fix. - * filesubr.c (mkdir_if_needed): Also check EACCES/isdir. Needed - to make toplevel-12 test work. - - * sanity.sh (toplevel): New test toplevel-11 and friends test for - another variation of the toplevel-9 bug. - -Tue Jul 29 12:11:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * login.c (construct_cvspass_filename): Revert this change. The - main reason is procedural; Karl is not a current CVS developer. - The other thing is that the new text doesn't say anything about - HOMEDRIVE and HOMEPATH. - -Tue Jul 29 11:36:22 1997 Karl Fogel <kfogel@harvey.cyclic.com> - - * login.c (construct_cvspass_filename): error message informs user - she may need to set HOME environment variable by hand. - -Sun Jul 27 15:36:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * admin.c (admin): Remove comment "XXX send -ko too with i = 0". - It turns out to be a description of a bugfix which was applied on - 8 Oct 1995, and never should have been in a comment in the first - place. - - * admin.c (admin, admin_fileproc): Parse options ourself rather - than blindly passing them to RCS. - Accordingly, add struct admin_data and function arg_add, and delete - global variables ac and av. - * sanity.sh (admin): Change admin-3 test to reflect cvs admin -i - now being an error. - (basicb): Change basicb-21 test to relect the improved error - message here. - -Sat Jul 26 11:34:51 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (join3): New tests, test a new branch topology and - greatest common ancestor. - -Fri Jul 25 09:51:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (serve_directory): Repository must start with - CVSroot_directory rather than some random pathname. - - * remove.c (remove_fileproc): If there is a numeric sticky tag, - don't allow the remove. - * commit.c (check_fileproc): Add comment about this case. - * sanity.sh (sticky): New tests sticky-15 through sticky-23 - test for this behavior and the analogous behavior with - non-branch sticky tags (which is unchanged). - - * client.c (update_entries): Clear the stored mode, modtime, and - checksum even on an error. - * sanity.sh (contents2-142d*): Also test cvs status. Also test - the case in which the contents of the file are unchanged. Also - test running diff to see the conflict, and resolving the conflict. - Without the fix above, the new contents2-142d2 test would get a - "duplicate Mod-time" warning. - -Thu Jul 24 13:29:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (pserver_authenticate_connection): Call parse_config - here too. - * parseinfo.c (parse_config): If we are called several times, the - times beyond the first do nothing. - * cvs.h, parseinfo.c (parse_config): New argument cvsroot. - * server.c, main.c: Update callers. - * server.c, server.h (system_auth): New variable. - * parseinfo.c (parse_config): Parse new keyword SystemAuth. - * mkmodules.c (config_contents): Add comments for SystemAuth. - * server.c (check_password): If !system_auth, then skip the check - for a system username/password. - - * main.c (main): No fatal error if parse_config returned an error. - * server.c (serve_root): Likewise. - * error.c (error): Add comment about calling from the server. - * parseinfo.c, cvs.h (parse_config): Remove NOERR crock. - Closer reading of server.c makes it seem like calling error - here is OK after all. - * sanity.sh (config): New test, tests for above fix. - - * server.c (serve_root): Fix typo ("doign" -> "doing"). - -Wed Jul 23 13:55:09 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * vers_ts.c (Version_TS): If entdata is for a directory, don't set - vn_user and friends. - * server.c (dirswitch): Add comment about why Subdir_Register is - sometimes a noop here. - * cvs.h (struct vers_ts): Fix comments about NULL vs. "" in vn_user. - * sanity.sh (errmsg2): New tests errmsg2-10 through errmsg2-12 test - for above fix. - * add.c (add_directory): Call cvs_output not printf. This fixes - an out-of-order bug which was showing up in the testcase. - -21 Jul 1997 Jim Kingdon - - * subr.c (get_file): Put st_size into an unsigned variable to - avoid signed/unsigned warnings. - -Mon Jul 21 00:19:30 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version number to 1.9.13. - - * Version 1.9.12. - - * sanity.sh (toplevel, head): Delete our files from the repository - when done with them. - -Sun Jul 20 15:53:08 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (admin, reserved): New tests, test most cvs admin - behaviors. - (log2): New tests log2-5 through log2-10 test setting the - description via cvs admin. - -Thu Jul 17 12:39:27 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (socket_buffer_input, socket_buffer_output): Add - comment regarding size of of buffer we pass to send and recv. - -Sat Jul 12 15:21:24 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * import.c, rcs.h (add_rcs_file): New argument key_opt replaces - access to global variable keyword_opt. New arguments desctext and - desclen allow one to set the description. If add_vhead is NULL, - then omit a revision, like rcs -i. - * import.c (process_import_file), mkmodules.c (init): Change - callers. - * subr.c, cvs.h (get_file): New function, adapted from code in - update_entries. - * client.c (update_entries): Call it. - * commit.c (checkaddfile): Create new RCS files with add_rcs_file - rather than rcs -i. - -Fri Jul 11 12:14:54 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (join_file): Handle binary files ourself rather than - passing them to RCS_merge (which sort of tries to handle binary - files, but does so badly). - * sanity.sh (binfile2): New "brmod", "brmod-trmod", and - "brmod-wdmod" tests test for this fix. - - * add.c (add): Exit status is now nonzero if any of the arguments - failed (already was mostly true, make it true for the new sanity - check). Move check for '/' (now ISDIRSEP) up to sanity check, so - the client does it too. - * sanity.sh (errmsg2): Test for this fix. - -Thu Jul 10 00:02:54 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add): Check for CVSADM, ".", and "..", and skip any - attempt to add them. - * sanity.sh (errmsg2): New tests, tests for above fix. - - * main.c (main): In text printed upon --version, also refer - people to --help. - - * rcscmds.c (RCS_exec_rcsdiff): Add comment about timezones. - - * server.c, cvs.h (cvs_output_binary): New function. - * rcs.c (RCS_checkout): For a binary file, call cvs_output_binary - rather than cvs_output. - * client.c (handle_mbinary): New function. - (responses): Add "Mbinary". - -Tue Jul 8 12:18:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * filesubr.c (get_homedir): Add comment about root vs. user - directory in pserver server. - -Mon Jul 7 14:39:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (big): Also test Rcs-diff case. - - * client.c (update_entries): Reindent a line. - - * sanity.sh (death2): Add comment about Sun diff. Thanks to - Warren Jones <wjones@TC.FLUKE.COM> for reporting this. - - * client.c (update_entries): If DONT_USE_PATCH, then just treat a - Patched response as an indication to try again with complete files. - * update.c (update): Remove DONT_USE_PATCH ifdefs, since a CVS - with DONT_USE_PATCH defined can still handle Rcs-diff. - * sanity.sh (serverpatch): Add comment about this coming up in - real life if the user modifies the file while CVS is running. - - * client.c (start_server): Add comment about logfiles if there are - several connections to the server. - (log_buffer_shutdown): Close the logfile after shutting down the - underlying buffer. This way at least we get the last set of - logfiles rather than a bizarre mishmash. - -1997-07-06 enami tsugutomo <enami@but-b.or.jp> - - * logmsg.c (do_verify): Unlink temporary file before call error(). - Remove unneeded `return' statement. Fix comment. - -Sun Jul 6 13:36:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * diff.c (diff_fileproc): Change message from "during rcsdiff of" - to "while diffing". For a while now, that message might be - printed after a call to DIFF instead of rcsdiff. - - * diff.c (diff_fileproc): Call cvs_output not printf. Remove - calls to fflush (should be handled now by call to cvs_outflush in - recurse.c). - * patch.c (patch_fileproc): Likewise. - - * rcscmds.c, cvs.h (diff_exec): New function. - * diff.c (diff_fileproc), patch.c (patch_fileproc), - update.c (patch_file): Call it. - - * rcscmds.c: Adjust comments concerning diff library to point to - new, expanded comments at diff_exec. Remove comments concerning - patch library; Rcs-diff should be adequate. - - * client.c (update_entries): Add comment about GNU patch usage (-b - option and so on). - -Sat Jul 5 04:13:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcscmds.c, cvs.h (RCS_exec_rcsdiff): New function. - * diff.c (diff_fileproc): Call it. - -Thu Jul 3 09:50:07 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): Add comment about how long we should keep the - deprecated "cvs rlog" alias. - - * server.c (cvs_output): Add comment about whether to fflush. - -Wed Jul 2 18:57:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (join2): New tests join2-19 and friends test for a - case that we can't readily get right (see comments). - -Tue Jul 1 09:52:09 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (cmd_usage): Say "specify" --help rather than the vague - "use". - (opt_usage, cmd_synonyms): Mention --help here too. - * add.c, admin.c, checkout.c, commit.c, diff.c, edit.c, import.c, - log.c, login.c, mkmodules.c, patch.c, rcs.c, release.c, remove.c, - rtag.c, status.c, tag.c, update.c, watch.c: Likewise, for all the - other help messages. - - * sanity.sh (join2): New tests. - - * repos.c (Name_Repository): Check for errors from fclose. - -Fri Jun 27 10:27:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * scramble.c, login.c: Reindent. - - * client.c (connect_to_pserver): Check for errors from send(). - If socket() fails, include SOCK_STRERROR (SOCK_ERRNO) in message. - -Wed Jun 25 11:21:52 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c: New option --help-options, with much of the text - from --help. Fix a few capitalization and punctuation problems. - Rewrite text for --help to be an intro to all the --help-* - options. - - * sanity.sh (head): New tests, concerning meaning of HEAD. - -Tue Jun 24 10:14:18 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (recv_line): New function. - (connect_to_pserver): Call it, and rewrite accordingly. Also - accept new "E" and "error" responses. Change \n to \012. - * server.c (pserver_authenticate_connection): Adjust comment - accordingly, concerning sending I HATE YOU not "error". - -Sun, 22 Jun 1997 Jim Kingdon - - * main.c (main): Move setting of server_active inside #ifdef - SERVER_SUPPORT; otherwise the variable doesn't exist. - * main.c (main): Call return after exit to shut up warning. - -Fri Jun 20 22:56:34 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (connect_to_pserver): On "I HATE YOU", give - "authorization failed" fatal error regardless of verify_only. - * login.c (login): Don't print that "incorrect password" message; - it now is possible with an --allow-root failure as well as an - incorrect password. cvsclient.texi doesn't really specify what I - HATE YOU means in any detail, and it seems a little silly for - login to give different messages than the other commands. - * client.c, client.h (connect_to_pserver): Return type now void. - -Thu Jun 19 12:16:10 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (serve_root): Give error on duplicate Root request. - Call parse_config. - * parseinfo.c, cvs.h (parse_config): New function. - * cvs.h (CVSROOTADM_CONFIG): Added. - * main.c (main): Set server_active here... - * server.c (server): ...not here. That seems cleaner than - strcmp's between command_name and "server" in main.c. - * main.c (main): Call parse_config. - * main.c, cvs.h (free_Rcsbin): Make global. - * mkmodules.c (filelist): Add CVSROOTADM_CONFIG. - -Wed Jun 18 11:24:31 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version number to 1.9.11. - - * Version 1.9.10. - -Tue Jun 17 22:48:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): Add --allow-root=ROOT argument; call - root_allow_add for each time it is specified. Call - root_allow_free before exiting. - * root.c, cvs.h (root_allow_add, root_allow_free, root_allow_ok): - New function. - * server.c (pserver_authenticate_connection): If root_allow_ok - doesn't like the CVSROOT directory, don't allow access. - -Tue Jun 17 14:30:14 1997 Jim Kingdon (unknown@beezley) - - * client.c: Add "copyright" notice. If NO_EXT_METHOD, omit - start_rsh_method. - * client.c (update_entries): Cast argument to MD5Update from - char * to unsigned char *. - -Mon Jun 16 16:46:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * run.c (piped_child, filter_stream_through_program): - If USE_SETMODE_BINARY, then put the pipes into binary mode. - * find_names.c, ignore.c, lock.c, wrapper.c: Change fnmatch to - CVS_FNMATCH. - * client.c (start_server): If NO_EXT_METHOD, then give a fatal - error on any use of :ext:. - -Sun Jun 15 22:30:27 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (toplevel): Match U CVSROOT/* lines with DOTSTAR in - test toplevel-9. - -Thu Jun 12 10:27:51 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (toplevel): Remove Emptydir before starting. - - * sanity.sh: Change "rm -rf" to "rm -r" when deleting working - directories (except a few watches cases). Helps detect cases - where the testsuite has cd'd to somewhere other than where we - think it has. - (basic2): Remove "rm -r first-dir" between tests 49 and 50. The - directory was already deleted in test 45.5. - (rcs): Add "cd .." at end of tests. - (stamps): No longer cd to TESTDIR; shouldn't be necessary with - fix to "rcs" test. - -Wed Jun 11 22:28:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basicb): Also remove CVSROOT/Emptydir at end of - test. Otherwise it affects the toplevel-9 test for remote. - -Tue Jun 10 14:03:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (toplevel): Change "update" and "checkout" to "[a-z]*" - as these read "server" instead for "make remotecheck". Change - expect strings for toplevel-9 to accept the behavior of remote CVS - (see comments for more discussion). - - * sanity.sh: New tests stamps-9 through stamps-11 test timestamp - behavior on cvs update. - -Mon Jun 9 22:42:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Remove "#! /bin/zsh" line at end. I assume it was - added accidentally. - -Tue Jun 10 03:08:46 1997 Norbert Kiesel <nk@psycho.de> - - * sanity.sh: new tests "toplevel" for the new toplevel CVS - directory creation (including one test which shows an error in - this area). - -Sun Jun 8 20:52:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.c (getrcsrev): Before printing error, check whether it was - feof or ferror. - - * rcs.h, import.c (add_rcs_file): No longer static. New arguments - add_vbranch, add_vhead, and add_logfp replace access to static - variables vbranch, vhead, and logfp. - * mkmodules.c: Call it instead of RCS_CI. - * import.c (process_import_file): Adjust call to add_rcs_file. - -Tue Jun 3 10:18:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basicb): Match "." with "\." not ".". - -Tue Jun 3 13:02:37 1997 Norbert Kiesel <nk@cosa.de> - - * checkout.c (checkout): Removed restriction of not sending -k in - remote export (I think this was introduced while the -k handling - was still broken in remote mode). Give better error texts - regarding -c and -s options. Use error() instead of usage() for - reporting errors in all places. Reindented some lines. Free - xmalloc'd space of options. - -Thu May 29 16:32:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcscmds.c (RCS_checkin), mkmodules.c (init): Pass -w option to - "ci", specifying getcaller (). - * server.h, server.c (CVS_Username): Now extern. - * subr.c (getcaller): Return CVS_Username if it is set. - -Wed May 28 22:31:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (update_fileproc): If wrap_merge_is_copy and we would - like to do a merge, give a fatal error. See comment for why. - * sanity.sh (mwrap): New tests, tests for above fix. - -Tue May 27 21:59:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (stamps): cd to ${TESTDIR} before starting. - -Mon May 26 15:31:30 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (handle_mod_time): New function. - (responses): Add "Mod-time". - (stored_modtime_valid, stored_modtime): New variables. - (update_entries): If it is set, change the file's modtime. - * server.c, server.h (server_modtime): New function. - * vers_ts.c (Version_TS): Call it. - * patch.c (patch_fileproc): Add comment about why we don't. - * sanity.sh (stamps): Added, tests for above fix. - -Fri May 16 13:14:30 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * subr.c (free_names): Update documentation to reflect fact that - free_names is now called to free vectors allocated by expand_wild - as well as by line2argv. - - * main.c (main): Use "xstrdup (foo)" not "xstrdup(foo)" as - specified in HACKING. - -Fri May 16 15:10:37 1997 Norbert Kiesel <nk@cosa.de> - - * modules.c (do_module): initialize optind to 0. use local copies - of optarg's (because they might me freed within free_names). - -Thu May 15 11:50:15 1997 Norbert Kiesel <nk@cosa.de> - - * main.c (main): initialize optind to 0. use local copies of - optarg's (because they might me freed within read_cvsrc). - - * cvsrc.c (read_cvsrc): free old argv after constructing a new - one. This fixes a memory leak. - - * recurse.c (start_recursion): use free_names() instead of - reimplementing it - - * rcs.c (RCS_deltas): free branchversion (memory leak). - - * parseinfo.c (Parse_Info): free some vars (3 memory leaks). - - * logmsg.c (logfile_write): free str_list_format (memory leak). - - * watch.c (watch_addremove), (watchers), update.c (update), tag.c - (cvstag), status.c (status), rtag.c (rtag), remove.c (cvsremove), - release.c (release), patch.c (patch), log.c (cvslog), import.c - (import), history.c (history), edit.c (watch_onoff), (edit), - (unedit), (editors), diff.c (diff), commit.c (commit), checkout.c - (checkout), add.c (add): initialize optind to 0 - - * diff.c (diff_fileproc): cosmetic change (whitespace added). - - * checkout.c (checkout): move local variable definition into the - block where the variable is used. - - * client.c (update_entries): initialize some local variables to shut up - gcc -O -Wall. - - * buffer.c (buf_read_line): initialize a local variable to shut up - gcc -O -Wall. - - -Wed May 14 16:29:50 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * admin.c (admin): When sending options to server, don't try to - send av[ac]. It may contain one of the names that we'll send in - send_file_names (which caused tests like keyword-6 to work, - sort of accidentally), or it may contain NULL (which would tend to - cause a coredump). - * sanity.sh (basicb): New test basicb-21 tests for above fix. - -Mon May 12 16:22:00 1997 Larry Jones <larry.jones@sdrc.com> - - * add.c (add): Free message and repository in client code. - * checkout.c (checkout): Don't free repository unless allocated. - * client.c (start_rsh_server): Free command. - -Sun May 11 11:43:54 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c: Remove all references to USE_DIRECT_TCP; see - ../ChangeLog for rationale. - -Fri May 9 22:19:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (main): Add comment explaining why we call exit. Pass 0 - not EXIT_SUCCESS, because lib/system.h has portability cruft for - EXIT_FAILURE but not EXIT_SUCCESS. - -Fri May 9 17:25:00 1997 Larry Jones <larry.jones@sdrc.com> - - Fix miscellaneous memory allocation problems: - * add.c (add): Free repository. - * client.c (notified_a_file): Free getline buffer. - * edit.c (notify_check): Free getline buffer. - * hash.c (dellist): Free header node when not caching. - * login.c (login): Don't continually free & allocate getline - buffer, use xstrdup instead of xmalloc/strcpy, free getline - buffer before returning. - * main.c (main): Call exit instead of returning so tools like - Purify won't consider permanently allocated memory as leaks. - * mkmodules.c (mkmodules): Free getline buffer. - * modules.c (cat_module): Call close_module. - * rcs.c (rcsvers_delproc): Free state. - * recurse.c (start_recursion): Free files_by_dir. - (unroll_files_proc): NULL out p->data after using it to set - filelist to avoid multiple frees. - * server.c (check_command_legal_p): Don't continually free & - allocate getline buffer, free getline buffer before returning. - (check_repository_password): Ditto, use xstrdup instead of - xmalloc/strcpy. - * wrapper.c (wrap_add_file): Free getline buffer. - -Thu May 8 14:21:00 1997 Larry Jones <larry.jones@sdrc.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (checkout_proc): Free finfo.rcs (memory leak). - -8 May 1997 Larry Jones <larry.jones@sdrc.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * hash.c: Add #ifdef's to disable caching. This makes it easier - to track down memory allocation problems. - -Thu May 8 11:40:39 1997 Larry Jones <larry.jones@sdrc.com> - - * sanity.sh: In setting "tests" use a number of statements rather - than one very long line. - -Thu May 8 11:40:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvsbug.sh: Remove $Id; we decided to get rid of these some time - ago. - -Thu May 8 11:34:02 1997 Larry Jones <larry.jones@sdrc.com> - - * cvsbug.sh: Put separate statements on separate lines, so it - works if awk is AT&T nawk. - -Tue May 6 16:56:00 1997 Larry Jones <larry.jones@sdrc.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvsrc.c (read_cvsrc): Fix various memory allocation problems: - rearrange code to avoid leaks, use xrealloc instead of xmalloc/ - copy/free, make sure there's room for the remaining args before - appending them. - -Tue May 6 14:20:00 1997 Larry Jones <larry.jones@sdrc.com> - - * edit.c (watch_onoff, edit, unedit, editors): Add -R like - other things with -l. - * watch.c (watch_addremove, watchers): Ditto. - -Mon May 5 18:10:37 1997 larry.jones@sdrc.com - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Change all /tmp/cvs-sanity to TESTDIR. If TESTDIR - environment variable is set, use it instead of /tmp/cvs-sanity. - * sanity.sh: Make TMPPWD the pwd equivalent of TESTDIR, not of /tmp. - -4 May 1997 Larry jones <larry.jones@sdrc.com> - and Jim Kingdon - - * checkout.c, diff.c, patch.c, rcs.c: Update usage messages. - * rcs.c (annotate): Add -R like other things with -l. - -Sat May 3 14:57:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basic1): Rewrite test (use dotest, unroll the loops - which IMHO makes the test a zillion times more understandable, and - only do the variant which tests for 4 files at a time--we test one - file at a time lots of places). - -2 May 1997 Ziv Gigus <ziv@rest.home.net> - and Jim Kingdon - - * client.c, client.h (client_process_import_file): New argument - all_files_binary means treat all files as binary. - * import.c (import_descend): Pass it if -kb is specified. - * client.c (client_process_import_file): In the - non-all_files_binary case, call wrap_rcsoption to determine - whether the file is binary. - -Thu May 1 13:44:51 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (binfiles2): New tests, for update -j and binary files. - -Wed Apr 30 11:18:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * recurse.c (start_recursion): Also free reposfile. - Don't look in repository if client_active (latter bug reported by Paul - Sanders <p.sanders@dial.pipex.com>). - -Mon Apr 28 22:36:39 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * diff.c (diff_file_nodiff): Remove SERVER_SUPPORT ifdefs. They - were not based on server_active, which doesn't really make any - sense (it meant that compiling --disable-server could affect the - behavior of the non-client/server CVS). This affected the output - in tests death2-diff-11 and death2-diff-12 in the testsuite. - * sanity.sh (newb-123j0): Also accept "Needs Checkout", for a - --disable-server CVS. - - * main.c (cmd_usage): Change "run diffs" to "show differences"; - the former is jargon. - * edit.c (edit_usage): Fix typo ("." -> ","). - * edit.c (editors_usage), watch.c (watchers_usage): Mention -l. - * checkout.c (export_usage): Say what -P does. - * history.c (history_usg): Add comment about message wording. - -Mon Apr 28 14:47:45 1997 Norbert Kiesel <nk@cosa.de> - - * checkin.c (Checkin): use filename without path when calling - wrapper (bug found by Michal Schmitz <ms@cosa.de>). - -Fri Apr 25 13:28:55 1997 Ian Lance Taylor <ian@cygnus.com> - - * client.c (update_entries): In UPDATE_ENTRIES_RCS_DIFF case, - write to a temporary file and then rename it. - -Thu Apr 24 11:35:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * subr.c, cvs.h (pathname_levels): New function, from a piece of - send_file_names. - * client.c (send_file_names): Call pathname_levels in place of the - code which was moved there. - * server.c, server.h (server_pathname_check): New function. - * recurse.c (start_recursion): Call it. - * sanity.sh (modules3): New test modules3-11b tests for above fix. - - * filesubr.c: Do not define L_tmpnam. It is in ANSI and SunOS4, - so I don't think there will be a problem with it being missing. - Defining it too small can cause memory corruption. - (cvs_temp_name): Do not use L_tmpnam in the mktemp code; this - could cause a buffer overflow if the -T global option was in use. - -Thu Apr 24 13:21:15 1997 Norbert Kiesel <nk@cosa.de> - - * filesubr.c (cvs_temp_name): Use tempnam if available, else - mktemp, else tmpnam. See the comment for rationale. - - * sanity.sh: use "tar cf - ." instead of "tar cf - *" for - directory copies. - -Wed Apr 23 23:41:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (serve_update_prog): If in readonly mode, give an error. - -Wed Apr 23 19:07:41 1997 Norbert Kiesel <nk@cosa.de> - - * subr.c (line2argv): Allocate at least 4 slots for argv. - - * checkout.c (checkout_proc): Add a comment which says why the - above change was necessary to avoid writing to unallocated memory. - -Wed Apr 23 11:20:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * entries.c (ParseTag): Always set *NONBRANCHP. - -21 Apr 1997 Jim Kingdon - - * client.c (update_entries), rcs.c (expand_keywords): Rewrite - test to avoid signed/unsigned warning. - -Mon Apr 21 09:02:22 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (patch_file): Add comment about whether auto-detecting - features of the DIFF program is a good idea. - -Mon Apr 21 00:03:34 1997 Ian Lance Taylor <ian@cygnus.com> - - Don't require the patch program: - * client.c (struct update_entries_data): Add - UPDATE_ENTRIES_RCS_DIFF to contents enum. - (update_entries): Handle UPDATE_ENTRIES_RCS_DIFF. - (handle_rcs_diff): New static function. - (responses): Add "Rcs-diff". - * server.c (server_updated): Handle SERVER_RCS_DIFF. - (server_use_rcs_diff): New function. - * server.h (enum server_updated_arg4): Add SERVER_RCS_DIFF. - (server_use_rcs_diff): Declare. - * update.c (rcs_diff_patches): New static variable. - (update): Set rcs_diff_patches. - (update_fileproc): If rcs_diff_patches, pass SERVER_RCS_DIFF - rather than SERVER_PATCHED to server_updated. - (patch_file): Correct initial comment to say diff rather than - rcsdiff. If rcs_diff_options, pass -n to diff rather than -c. - * rcs.c (rcs_change_text): New function. - * rcs.h (rcs_change_text): Declare. - -Mon Apr 21 00:08:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * diff.c (diff_fileproc): Add comment concerning updating the - client timestamp. - -Sun Apr 20 23:20:37 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * commit.c (commit): Add comment regarding SEND_FORCE rationale. - -Sat Apr 19 17:10:36 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (dirswitch): If directory ends in '/', complain. - -Fri Apr 18 18:09:57 1997 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (apply_rcs_changes): New static function, broken out of - RCS_deltas. - (RCS_deltas): Call it. - (linevector_add): Change return type to int. Return an indication - of an error for an invalid add, rather than calling error. - -Fri Apr 18 11:24:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version number to 1.9.9. - - * version.c: Version 1.9.8. - - * commit.c (struct find_data): Add field force. - (find_fileproc, commit): Use it instead of force_ci to decide - whether to send files to server. - (commit): Set it if either -f or -r is specified. - * sanity.sh (basica): Add tests basica-8a0, basica-8a1, and - basica-8a2; tests for above fix. - -Wed Apr 16 11:50:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * zlib.c: Remove paragraph with Free Software Foundation address. - See 2 Jan 1997 entry in ../ChangeLog for rationale. - -Tue Apr 15 00:36:23 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (patch_file_write): Always assign to final_nl, so that - it ends up reflecting whether the data from the last call had a - newline, not whether the data from any of the calls ended in a - newline. Doesn't matter with the current RCS_checkout - implementation, but it will if RCS_checkout is changed to pass - less than the entire file. - - * rcs.c (RCS_cmp_file): Change NULL to RUN_TTY in passing sout to - RCS_checkout, for clarity. - - * import.c (update_rcs_file): Remove unused variable ierrno. - - * add.c, checkout.c, commit.c, diff.c, edit.c, import.c, - history.c, log.c, main.c, patch.c, release.c, remove.c, rtag.c, - status.c, tag.c, update.c, watch.c: Pass "+" to all calls to - getopt. This ensures that we maintain existing behavior even with - glibc2. - - * filesubr.c (fopen_case): Don't set *PATHP if we return an - error. Since the 9 Apr 1997 change, the behavior has been to - sometimes set it and sometimes not. - * rcs.c (RCS_parse): Adjust callers to not free it. Without this - change, they could call free() on an uninitialized variable. - - * checkout.c (checkout): Add comment about export -k. - - * root.c (check_root_consistent): Add comment about wording of - message. - -Mon Apr 14 11:51:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (call_in_directory): If rdirp reaches the end of - reposdirname, then just set it to NULL. If server does not create - directories one at a time, give a warning. - * sanity.sh (modules3): Enable tests modules3-8 through - modules3-11 for remote; tests for above fix. - - * client.c (call_in_directory): Don't set short_pathname to - pathname for a while; just use pathname itself (cleans up a relic - of the old "Repository" (not "Directory") code). Add comment - explaining short_pathname. - -Sun Apr 13 18:07:50 1997 Ian Lance Taylor <ian@cygnus.com> - - * rcs.c (RCS_checkout): Add pfn and callerdat parameters. Change - all callers. Move setting of expand after retrieval of file - data. - (struct cmp_file_data): Define. - (RCS_cmp_file): New function. - (cmp_file_buffer): New static function. - * rcs.h (RCSCHECKOUTPROC): Define type. - (RCS_checkout): Update declaration. - (RCS_cmp_file): Define. - * diff.c (diff_file_nodiff): Call RCS_cmp_file rather than - RCS_checkout and xcmp. - * import.c (update_rcs_file): Likewise. - * no_diff.c (No_Difference): Likewise. - * update.c (struct patch_file_data): Define. - (patch_file): Just return if noexec, or if binary file. Pass - patch_file_write to RCS_checkout. Don't check for newlines or - compute checksums here. Stat RCS file to set modes. - (patch_file_write): New static function. - - * update.c (patch_file): Checkout directly to file2, rather than - to finfo->file followed by rename. Remove check for whether - result of checkout is readable; that was for an old, obsolete, - form of death support. - -Sun Apr 13 13:16:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (build_one_dir): New function. - (struct dir_to_build): New structure. - (build_dirs_and_chir): Rewritten to accept a linked list of struct - dir_to_build rather than the silly string processing we had been - doing before. - (checkout_proc): Rewrite code that calls build_dirs_and_chdir - accordingly. - * sanity.sh: Enable tests modules3-10 and modules3-11 for local CVS; - tests for above fix. - - * rcs.h (RCS_CO): Removed; no longer used. - -Sun Apr 13 00:04:34 1997 Ian Lance Taylor <ian@cygnus.com> - - Expand RCS keywords internally; never call co: - * rcs.h (struct rcsversnode): Add state field. - * rcs.c (kflags): Move out of RCS_check_kflag, and make file - static. - (enum kflag): Define. - (RCS_reparsercsfile): Always save lock information. Save state in - new state field, rather than other field. - (struct rcs_keyword): Define. - (keywords): New static variable. - (enum keyword): Define. - (printable_date, escape_keyword_value): New static functions. - (expand_keywords): New static function. - (RCS_checkout): Call expand_keywords. Don't call - RCS_exec_checkout. - (RCS_deltas): Add log and loglen parameters. Change all callers. - * log.c (log_version_requested): Use new state field. - (log_version): Likewise. - * cvs.h (RCS_exec_checkout): Don't declare. - * rcscmds.c (RCS_exec_checkout): Remove. - -Sat Apr 12 17:32:59 1997 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh (modules3): Remove second-dir at end of tests. - (sticky): Correct removal of directories at end of tests. - - * sanity.sh (keyword): New tests for RCS keyword expansion. - -Sat Apr 12 16:47:13 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basicb): New tests basicb-1b, basicb-1c, basicb-9b, - basic-9c test current build_dirs_and_chdir behavior. - -Fri Apr 11 23:54:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (modules3): New tests modules3-7* test for ability to - supply a path in -d in modules. Similar to modules3-8 through - modules3-11 except because the nesting is different, these ones - work. - -Thu Apr 10 00:14:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (modules3): New tests modules3-12 through modules3-15 - test use of a module name which contains a slash. - - * sanity.sh (basicb): New tests basicb-14 to basicb-20 test use of - co -d with two or more arguments. - - * rcscmds.c: Refer to doc/RCSFILES in comment. - -Wed Apr 9 09:49:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basicb): New tests basicb-11 through basicb-13 test - ability to specify several directory levels in co -d (commented - out). - - * filesubr.c (fopen_case): If CVS_OPENDIR gives an - existence_error, return it to the caller instead of giving a fatal - error. - - * client.c (update_entries): Fix typo in call to error (1 -> errno). - -Tue Apr 8 23:02:22 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * error.h, error.c: Test for #ifdef __STDC__, not #if __STDC__. - This is consistent with other parts of CVS; it means that the - declaration for fperror will match the definition even if __STDC__ - is defined to 0 as the SunPro 4.0 compiler does. Reported by - Richard Smith <rjsmith@cisco.com>. - -2 Apr 1997 Jim Kingdon - - * entries.c (ParseTag): Add "break;" after "default:" to avoid - error from Visual C++. - -Wed Apr 2 12:06:44 1997 Vince Del Vecchio <vdelvecc@spd.analog.com> - and Jim Kingdon - - * client.c: In reporting errors from socket calls, use - SOCK_STRERROR and SOCK_ERRNO since strerror(errno) doesn't work - for Win32. - -Tue Apr 8 10:45:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (modules3): Add tests modules3-8 to modules3-11, to - test for ability to supply a path to -d in modules. Mostly - commented out as CVS is buggy in this area. - -Mon Apr 7 12:41:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add): Add comment about SEND_NO_CONTENTS. - -Sun Apr 6 21:46:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (update): Add comment about noexec and SEND_NO_CONTENTS. - -Sun Apr 6 17:34:08 1997 Robert Bihlmeyer <robbe@orcus.priv.at> - - * Pass +f not f to getopt_long to prevent options from being - permuted with glibc 2.0.1. - -Sun Mar 30 00:07:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h (struct vers_ts): Adjust comment regarding ts_user. - * server.c (serve_is_modified): New function. Set entries to show - that the file is modified but we don't know the contents. - * server.c (requests): Add "Is-modified" request. - * vers_ts.c (time_stamp_server): If the timestamp in entdata is - "M" or "D", just copy that over into ts_user. - * vers_ts.c (Version_TS): If timestamp is "D", use the entries - line for the sole purpose of passing it to time_stamp_server. - * no_diff.c (No_Difference): If ts_user is "M", conclude the files - are different. - * client.h, client.c (send_files): Replace arguments build_dirs - and force with argument flags. Add flag SEND_NO_CONTENTS and add - to struct send_data. - (send_fileproc): If no_contents, then send Is-modified instead of - Modified. - * add.c, admin.c, client.c, commit.c, diff.c, edit.c, log.c, - rcs.c, remove.c, status.c, tag.c, update.c, watch.c: Change all - send_files callers. - -Fri Mar 28 22:32:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (requests): Change "Repository" to rq_optional. I'm - not sure whether I overlooked this when I removed support for - Repository, or whether I was thinking that servers would need to - support it anyway, for CVS 1.5 to 1.9 clients, but making it - optional doesn't prevent the server from supporting it and it - seems silly for the client to complain about absence of a request - that it never will use. - -Fri Mar 28 10:06:59 1997 Steven Miller <Miller@wingra.com> - - * entries.c (Subdirs_Known): Don't create Entries.Log if noexec. - -Thu Mar 27 18:14:12 1997 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh (death2): Remove commented out test death2-21. It - would now pass, but it duplicates the new test sticky-11. - -Thu Mar 27 10:21:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (dotest_internal): Write test output to logfile even - if test succeeds. This was the behavior prior to 30 Sep 1996. - See the comment for rationale. - -Tue Mar 25 13:26:52 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h, entries.c (WriteTag): Add arguments nonbranch, - update_dir, and repository. Move the server_set_sticky call from - callers to here. - * cvs.h, create_adm.c (Create_Admin): New argument nonbranch. - * cvs.h, entries.c (ParseTag): Add argument nonbranchp. - * cvs.h (struct stickydirtag): Add field nonbranch. - * entries.c (Entries_Open): Set it. - * cvs.h (Vers_TS): Add field nonbranch. - * vers_ts.c (Version_TS): Copy it from struct stickydirtag. - * server.c, server.h (server_set_sticky): Add argument nonbranch. - * add.c, client.c, checkout.c, modules.c, update.c, create_adm.c, - commit.c: Update callers. - * add.c (add): If nonbranch, don't add the file on that "branch". - * commit.c (write_dirnonbranch): New variable. - (commit_fileproc, commit): Set it. - (commit_dirleaveproc): Pass it to WriteTag. - * update.c (rewrite_tag, nonbranch): New variables. - (update, update_dirent_proc, update_fileproc): Set them. - (update_filesdoneproc): If rewrite_tag, call WriteTag. - * sanity.sh (sticky): New tests, test for above fix. - - * version.c: Change version number to 1.9.7. - - * version.c: Version 1.9.6. - -Mon Mar 24 13:02:04 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * entries.c (ParseTag): Add comment about unrecognized characters - in CVS/Tag file. - - * classify.c (Classify_File): Add comment about how specifying a - tag (bogusly?) suppresses certain messages. - -Fri Mar 21 13:37:46 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * rcs.h (struct rcsnode): Add comment about case of PATH. - * rcs.c (RCS_parse): If ign_case, then try opening the file with - fopen_case. - * ignore.c (ign_case): Adjust comment. - * cvs.h, filesubr.c (cvs_casecmp, fopen_case): New functions. - -20 Mar 1997 Jim Kingdon - - * client.c (send_repository): When sending Directory request, - send any ISDIRSEP character as '/'. Fixes - "cvs log foo\bar\baz.c" on NT & friends. - - * client.c (send_file_names): Don't try to read Entries file if - CVSADM directory does not exist. Fixes fairly serious regression - (warning on all fresh checkouts) introduced by 1997-01-08 change. - -Tue Mar 18 13:03:33 1997 Jim Meyering <meyering@totoro.cyclic.com> - - * sanity.sh (RCSINIT): Define to be empty and export, to hide any - existing value that might cause spurious failures. - - * Makefile.in: (install): Depend on installdirs. - Remove `CYGNUS LOCAL' comment saying not to. - -Tue Mar 18 09:36:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * recurse.c (struct recursion_frame): Reindent. - (do_dir_proc): Print message if we try to recurse into a CVSADM - directory. - * sanity.sh (basicb): New test basicb-4a tests for above fix. - -Sun Mar 16 10:18:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (death2): Replace regexp matching temporary file name - with new variable ${tempname}. For most of the tests this is a - cosmetic change, but death2-diff-6 had been missing _ which caused - it to fail on Solaris (at least sometimes). - - * sanity.sh (modes): Don't use export -n; it doesn't seem - to be sufficiently portable. - - * version.c: Change version number to 1.9.5. - - * version.c: Version 1.9.4. - - * rcscmds.c (RCS_checkin): Preserve the mode of the rcsfile. - RCS_CI usually, but not always, does this for us. - * commit.c (fix_rcs_modes): Replace algorithm with a more - CVSUMASK-friendly one. - * sanity.sh (modes): Update tests modes-5, modes-7, modes-10, and - modes-15 so they test that CVSUMASK is honored. - -Sun Mar 16 10:18:28 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (modes): New tests modes-7a and modes-7b test behavior - if one manually changes the modes in the repository. - - * server.c (server): Revise code which checks for errors creating - temporary directory. This won't solve the intermittent - can't create temporary directory - Unknown error -1 - but it will mean (a) the right message based on errno gets - printed, instead of "unknown error -1", and (b) the message says - that it happened in chmod instead of mkdir_p. - -Sat Mar 15 16:47:12 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (modes): New tests. Note that (for now) these are - just testing how CVS already behaves; I want to record that before - I move on to changing CVS's behavior with modes of RCS files. - -13 Mar 1997 Jim Kingdon - - * subr.c (line2argv): Change argv_allocated from size_t to int. - -Wed Mar 12 22:16:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add_directory): If repository has an extraneous "." - directory at the end, strip it off. This fixes a bug which was - introduced when strip_path was nuked (this fix is much more - limited in scope than strip_path was; I _think_ that is a good - thing). - (add): Likewise, for client. - (combine_dir): New function, helps with above. - * sanity.sh (modules3): Reenable tests for this behavior. - (basica-0b, basicb-0e): Adjust test to reflect "foo/bar" instead - of "foo/./bar" in message. As with the rest of this, I believe - this is just restoring the behavior prior to the strip_path nuking - (I tried it with CVS 1.9). - -Sun Mar 9 10:06:29 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * root.c (parse_cvsroot), server.c (serve_root, serve_init): - If CVSroot_directory is not an absolute pathname, give a fatal error. - * sanity.sh (crerepos): New tests crerepos-6* test for above fixes. - -Sat Mar 8 22:06:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - This cleans up the last known code which can overflow its buffers - (except the Mac client). I've skimmed through much of CVS looking - for other such places; but I didn't read everything. If I missed - any please report it to bug-cvs. - * logmsg.c (logfile_write, title_proc): Realloc str_list as - needed; don't assume MAXLISTLEN is enough. - * cvs.h (MAXLISTLEN, MAXFILEPERDIR): Removed; no longer used. - * add.c, myndbm.c, parseinfo.c, update.c: Nuke MAXLINELEN limit. - * parseinfo.c, update.c, mkmodules.c: Check for errors reading file. - * cvs.h (MAXLINELEN): Removed; no longer used. - * logmsg (MAXHOSTNAMELEN): Removed; not used. - * main.c (cmd_synonyms): Allocate based on fullname, nick1, and - nick2, just in case someone makes those big enough so that 100 - bytes is not enough. - (Make_Date): Use MAXDATELEN rather than our own fixed size. - * mkmodules.c (mkmodules): Nuke arbitrary limit on line length. - * rcs.c (ALLOCINCR): Remove; not used. - (RCS_check_kflag): Add comment concerning karg size. - * run.c: Allocate run_prog to the needed size, rather than - allocating a fixed size buffer. - -Fri Mar 7 22:39:08 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * logmsg.c (logfile_write): Allocate prog to needed length rather - than assuming MAXPROGLEN is enough. - * cvs.h (MAXPROGLEN): Removed; no longer used. - * subr.c (MIN_INCR): Update comment to reflect MAXPROGLEN's demise. - - * subr.c (free_names): Fix comment: this function is not used to - free memory allocated by Find_Names (at least it hasn't for a long - time). - * subr.c, cvs.h (line2argv): Change calling convention so that we - allocate argv array rather than the caller. The previous one had - no way of checking whether we overflowed the passed-in buffer. - * subr.c (free_names): Free the argv array too. - * modules.c (do_module, cat_module): Update callers. - -Thu Mar 6 12:44:42 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * import.c: Allocate vhead and vbranch dynamically; removes - arbitrary limit. - * history.c: Likewise (since_rev, since_tag, backto, rec_types). - * ignore.c: Likewise (line). Also check for errors from getline - and add 'copyright' notice to top of file. - * wrapper.c (wrap_add_file): Likewise (line). Also check for - errors from various calls and add 'copyright' notice to top of file. - -Tue Mar 4 17:39:15 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (update_entries): Add comment about "move away <file>" - message. - -Mon Mar 3 21:51:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basicb): Clean up topfile,v at end of test. Fixes - failure in modules-155b. - -Sun Mar 2 18:11:09 1997 Dan Wilder <dan@gasboy.com> - and Jim Kingdon - - * admin.c (admin): Arrange to perform recursion if "cvs admin" - is passed only options. - -Sun Mar 2 18:11:09 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (basicb): New tests basicb-0* test for files at top - level. - - * error.c (error): Add newline to "out of memory" message. I think - that its omission probably could cause the message to be lost in - the bowels of server.c and never passed to the user. - - * client.c (start_rsh_server): Add comment about "remsh" vs. "rsh". - - * cvs.h: Move copyright notice to top of file. - -Sun Mar 2 13:44:36 1997 Ian Lance Taylor <ian@cygnus.com> - - * sanity.sh: Use -n when testing whether rsh works. - - * server.c (serve_root): Free path. - -Sun Mar 2 13:12:46 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - The following are things that I noticed in the process of trying - to track down: - can't create temporary directory - Unknown error -1 - FAIL: test 28 - from nightly testing. I'm not sure that either item explains that - message however. - * server.c (server): Allocate pending_error_text; - print_pending_error will try to free it so - pending_error_text = "foo" - won't work. - (mkdir_p): Don't assume that isdir will leave errno unmolested. - -Thu Feb 27 15:29:58 1997 Ian Lance Taylor <ian@cygnus.com> - - * remove.c (cvsremove): When forcing removal in client mode, use - start_recursion rather than calling CVS_UNLINK on each argument. - (remove_force_fileproc): New static function. - * sanity.sh (deep): Add tests deep-rm7 through deep-rm10 for above - patch. - - * sanity.sh (death): Enable death-76a0 and death-76a1 tests for - remote, since they now work. - -Wed Feb 26 16:13:26 1997 Ian Lance Taylor <ian@cygnus.com> - - * client.c (add_prune_candidate): Skip adding this directory if - it is the same as the first directory already on the list. - -Mon Feb 24 21:36:43 1997 Noel Cragg <noel@gargle.rain.org> - - * main.c (lookup_command_attribute): Add the "init" command to the - list of commands that don't use the current working directory. - -Sun Feb 23 09:54:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (devcom3): Clean up at end of test. - - * sanity.sh (basicb): Add commented out test basicb-8a0, for - whether CVS can print an error on bad numeric revision to diff. - Commented out until we get around to fixing CVS. - * diff.c (diff_file_nodiff): Add comment about this case. - - * fileattr.c (fileattr_read): If a filename is duplicated, - continue to ignore subsequent lines but free the node so that we - don't leak memory. - * sanity.sh (devcom3): New tests devcom3-8 and devcom3-9 test for - behavior on duplicated filenames. - - * fileattr.h: Add comment about unrecognized ENT-TYPE and order of - lines in fileattr file. - * fileattr.c (struct unrecog, unrecog_head): New variables, to - record unrecognized lines. - (fileattr_startdir): Assert that unrecog_head == NULL. - (fileattr_read): Record unrecognized lines in unrecog_head linked - list rather than ignoring them. - (fileattr_write): Also write out unrecognized lines, if any. - * sanity.sh (devcom3): New tests, test for above fix. - - * fileattr.h (fileattr_modify): Fix example in comment. - -Sat Feb 22 08:30:27 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Add variable username. - (basica rdiff multibranch log log2): Use it instead of our own - (inconsistent) ways of matching an author name. - - * filesubr.c, root.c, rtag.c, server.c, subr.c, update.c, - wrapper.c: Nuke PATH_MAX. - * cvs.h, wrapper.c (wrap_fromcvs_process_file): Now returns void - (return value had been unused). - * cvs.h: Adjust comment to reflect the fact that PATH_MAX is - gone, at least from src/*.c (except safe_location, as noted). - -22 Feb 1997 patch by Tom Hageman <tom@basil.icce.rug.nl> (4 Jun 1996) - updated and commented by Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (checkout_file): Call unlink_file_dir on backup, not - unlink_file. - -Fri Feb 21 16:40:03 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in (DISTFILES): Remove NOTES. - - * NOTES: Removed. bcopy->memcpy is done. "static buffers" I - assume refers to what is covered by reentrancy text in HACKING. - Obstack idea moved to comment in hash.c (at nodecache). Checking - system calls for error returns largely done, and isn't a very - helpful suggestion unless you know where the bogus calls are - anyway. Sizing limits--we're in the progress of removing them - (assuming it meant things like PATH_MAX and earlier, already - nuked, limits). Removed various items about changes which were - done a long time ago (I realize that the ChangeLog's probably - aren't reliable that far back, but I'm not convinced anyone cares - anymore). CONFIRM_DIRECTORY_ADDS: I assume this is a - reference to the #if 0'd code in add_directory which asks for - confirmation--a better way of making it harder to accidentally add - directories would be to have to add and commit directories like - for files. I don't know what FORCE_MESSAGE_ON_ADD meant. - - * rcs.c (RCS_getrevtime): Fix documentation (in particular, the - size of the array that DATE must point to, but many other things - too). - * patch.c, recurse.c, release.c, remove.c, repos.c: Nuke PATH_MAX. - (patch_fileproc): Use MAXDATELEN not hardcoded 50. - -Sun Feb 16 12:00:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (client_process_import_file): New variable fullname; - pass it to send_modified. This finishes the job of untangling the - old short_pathname variable into update_dir vs. fullname. - - * client.c (client_process_import_file): Nuke first_time. If - toplevel_repos were ever NULL here, the code would dump core in - strncmp a few lines down. And client_import_setup ensures - toplevel_repos is not NULL. - -Sun Feb 16 08:16:48 1997 Ian Lance Taylor <ian@cygnus.com> - - * client.c (client_process_import_file): Rename short_pathname to - update_dir (to reflect its function) and make sure that it doesn't - point to uninitialized memory if repository and toplevel_repos - contain the same string. - -Sun Feb 16 08:16:48 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (start_rsh_server): Nuke comment about weirdnesses with - pre-1.5 versions of CVS and .bashrc/.cshrc. The remote protocol - is interoperable only back to 1.5, and people who need to know are - unlikely to see this comment anyway. - -Sun Dec 15 13:12:30 1996 Michael Douglass <mikedoug@texas.net> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * main.c (cmds): Added an entry for new logout command. - (cmd_usage): Added an entry for new logout command. - (lookup_command_attribute): Added 'logout' to list of commands - that set need_to_crate_root to 1. - * login.c, cvs.h (logout): New command for removing entries from - the .cvspass file. - (logout_usage): Usage information on the logout command. - -Wed Feb 12 11:19:42 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (struct send_data): Fix indentation. - -Wed Feb 12 08:48:04 1997 Greg A. Woods <woods@most.weird.com> - - * mkmodules.c (loginfo_contents): add missing comma in - initializer statement (caused syntax error on SunOS-4). - -Tue Feb 11 21:14:28 1997 Ian Lance Taylor <ian@cygnus.com> - - * commit.c (find_fileproc): If force_ci is set, set the status to - T_MODIFIED even if the file hasn't changed. - (commit): Pass force_ci to send_files as new force argument. - * client.c (struct send_data): Define. - (send_fileproc): The callerdat parameter now points to a send_data - struct. If force is set, always call send_modified. - (send_dirent_proc): The callerdat parameter now points to a - send_data struct. - (send_files): Add force parameter. Change all callers. Set up a - send_data struct and pass it to start_recursion as callerdat. - * client.h (send_files): Update declaration. - * sanity.sh (basica): Add a simple test for the above patch. - -Sun Feb 9 12:58:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * tag.c (cvstag), rtag.c (rtag): Pass -f to server if specified in - the client. I haven't tried to come up with a test case because - the fix seems obvious. - - * import.c (add_rcs_file): Change size of altdate1 and altdate2 to - MAXDATELEN. - * cvs.h (MAXDATELEN): Fix comments; describe what this is for. - - * diff.c (diff_usage): Document --ifdef and try to briefly say - what "rcsdiff-options" means. - - * update.c (update): If update had a nonzero status and we haven't - yet tried to fetch unpatchable files, go ahead and try it again. - The previous behavior was to quit, which meant that updates would - keep failing until you hacked around the problem. Patch and bug - report by Ian; comment, ChangeLog entry, and willingness to take - the flak if checking it is premature by Jim. - - * server.c (alloc_pending): New function. - * server.c: Call it. Fixes places where we had neglected to - check for NULL return from malloc. - - * sanity.sh (binwrap): Add test binwrap-0, tests for import.c fix - below. - -Sun, 9 Feb 1997 (submitted 19 Jul 1996) John Polstra <jdp@polstra.com> - - * import.c (import): Give error if the same tag is specified more - than once. The previous behavior was to write an RCS file which - had the same tag listed twice, once pointing to each revision, - which is not legal. - -Sun Feb 9 12:37:09 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * checkin.c (Checkin): Use cvs_output to print message (should - make out of order bugs no worse, as it merely substitues a - protocol_pipe vs. stderr_pipe race instead of a stdout_pipe - vs. stderr_pipe race). Add comment about stdout vs. stderr. - -Fri Feb 7 08:29:52 1997 Josef Nelissen <josef.nelissen@munich.ixos.de> - - * server.c (check_command_legal_p): Don't use ANSI-style definition. - -Thu Feb 6 10:55:37 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * patch.c (patch): Give a fatal error for -V option (see comment - for rationale). - - * diff.c (diff): Also send "options" to server. Pretty much the - patch submitted independently by josef.nelissen@munich.ixos.de and - Ronald Khoo <ronald@demon.net>. - -Wed Feb 5 18:57:14 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * modules.c (do_module): Fix typo in 30 Jan 97 PATH_MAX nuking - (free -> free_cwd). Testsuite test 151 gets credit for catching - this one. - -Mon Feb 3 16:14:54 1997 Ian Lance Taylor <ian@cygnus.com> - - * main.c (lookup_command_attribute): Don't use an ANSI prototype - when defining the function. - -Fri Jan 31 12:49:02 1997 Ian Lance Taylor <ian@cygnus.com> - - * modules.c (do_module): Actually goto found if is_found is set - (fixes thinko in PATH_MAX nuking of 30 Jan 97). - -Fri Jan 31 12:49:02 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Add modules3 and big to list of tests to run - by default; they were omitted by accident. - -Thu Jan 30 11:46:33 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * logmsg.c, main.c, mkmodules.c, modules.c, parseinfo.c, patch.c: - Nuke more PATH_MAX. - - * server.c (server_updated): After we send Created or - Update-existing for a file, mark it as unchanged, in case we - process it again. - * sanity.sh (modules3): New tests, test for above fix. - - * logmsg.c (do_verify): Error return from fopen is NULL, not -1. - Pass errno to error(). - - * login.c [_CRAY]: Don't declare getpass. - -Mon Jan 27 17:25:27 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * import.c (process_import_file): Fix freeing of rcs (Don't free - it before we are done using it, and don't free it twice). - - * modules.c (cat_module): Allocate line right before we use - it. The previous code was wrong because the length of the - s_h->rest changes between the time we allocate line and the time we - sprintf s_h->rest into it. - -Sun Jan 26 21:58:16 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * expand_path.c (expand_path): Revise to call expand_string as - needed. Nuke PATH_MAX. - * find_names.c (find_dirs): Likewise. - * import.c, lock.c: Nuke more PATH_MAX. - - * server.c (mkdir_p): Set retval to 0 at start of function. - Previously it had been uninitialized for some cases. Thanks are - due to nightly testing for catching this one. - -Sat Jan 25 21:34:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * subr.c, cvs.h (expand_string): New function. - * rcs.c (getrcskey, getrcsrev): Call it. This greatly reduces the - number of calls to realloc if there is a very large file in the - RCS file. Credit goes to Mike Heath <mike@pswtech.com> for - pointing out the problem and the basic solution (MIN_INCR, - MAX_INCR); I adapted it into the separate function expand_string. - * sanity.sh (big): New test helps insure this hasn't broken - anything obvious. - -Wed Jan 22 10:06:13 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * status.c (status_fileproc): Change message which is printed for - T_MODIFIED and ts_conflict set, so that it doesn't say "unresolved - confict". This message occurs whether the conflict is resolved or - not. - * sanity.sh (conflicts): Add tests conflicts-status-* to test - output of "cvs status" in the context of conflicts. Tests for - above fix. - - * rtag.c (rtag): Send -n if run_module_prog is NOT true. - -Thu Jan 16 00:06:00 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version number to 1.9.3. - - * version.c: Version 1.9.2. - -Wed Jan 15 09:14:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (call_in_directory): Take code that creates CVSADM at - top level, move it before the CVS_CHDIR (dir_name) call, and do it - regardless of whether dir_name is ".". Pass "." not dir_name to - Create_Admin (when the code was written they were always the - same). Don't add reposdirname to the repository we pass to - Create_Admin (when the code was written, I think reposdirname - probably would always be "."). Don't create CVSADM if - reposdirname_absolute. - * sanity.sh (basicb): Enable tests basicb-1a and basicb-9a for - remote; tests for above fix. - (basic1): Do entire test within a "1" directory to deal with - creation of CVS directories at top level. Support --keep. - (conflicts): In test conflicts-136, only update first-dir. - (basica): Uncomment the part that tests "cvs co -l .". That tests - the existing functionality which I might have (but hopefully did not) - perturbed with the call_in_directory changes. - -Mon Jan 13 11:04:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (check_command_legal_p): Do not call error (1, ...) - here; that will always cause a protocol violation by shutting down - the connection prematurely. Remove croak_on_illegal arg. - (do_cvs_command): Move call to check_command_legal_p until after - the call to print_pending_error. Print the error message ourself. - - * mkmodules.c (filelist): Add readers and writers. Add comment - about why passwd is not included. Add comment about meaning of - NULL contents field. - -Fri Jan 10 13:23:09 1997 Norbert Kiesel <nk@col.sw-ley.de> - - * release.c (release): Initialize delete_flag before reading it - (found by running purify) - - * logmsg.c (do_verify): Fix reading unallocated memory (found by - running purify) - -Thu Jan 9 16:32:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (build_dirs_and_chdir): Partially revert 3 Jan - change--move call to Subdir_Register back above the CVS_CHDIR call - (we need to register in the old, not the new, directory). Instead - of calling CVS_MKDIR and ignoring errors, call mkdir_if_needed; - this is an effort to catch errors there rather than catching them - in the CVS_CHDIR. This makes test 27-add-add in sanity.sh work - again. - - * find_names.c (Find_Directories): Remove code inside - #ifdef ATTIC_DIR_SUPPORT and replace it with a comment explaining - why we don't look in the attic. ATTIC_DIR_SUPPORT was never defined. - - * find_names.c (find_dirs): Add comment about tmp being unset. - - * commit.c (checkaddfile): Report errors with errno and specific - error messages. - - * rcs.c, commit.c, create_adm.c, entries.c, find_names.c, - ignore.c, history.c: Nuke PATH_MAX arbitrary limits. - -Wed Jan 8 23:07:41 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * add.c (add): Reindent a portion which needed it. - -1997-01-08 Jim Kingdon - - * client.c (send_file_names): When looking name up in Entries, - call Entries_Open and Entries_Close. This has two effects: - (1) we look at Entries.Log, and (2) we don't skip 'D' entries, - both of which are needed to make us get the right (command - line) name for a directory we are adding. - -Wed Jan 8 14:50:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in, cvs.h, hash.h, myndbm.h, rcs.h: Remove CVSid; we - decided to get rid of these some time ago. - -Tue Jan 7 12:56:10 1997 Karl Fogel <kfogel@ynu38.ynu.edu.cn> - - * root.c (check_root_consistent): new func, compares below new - global var with CVSroot_directory, assuming both set. - (set_local_cvsroot): use above new func for security check. - (parse_cvsroot): same. - But do all of above only #ifdef AUTH_SERVER_SUPPORT. - - * server.c: (Pserver_Repos): new global var, init to NULL. - (pserver_authenticate_connection): set above new global. - (check_repository_password): be a good scout and use - CVSROOTADM and CVSROOTADM_PASSWD, now that they are the standard. - Make sure all of above is in #ifdef AUTH_SERVER_SUPPORT. - (check_command_legal_p): wrap most of body in #ifdef - AUTH_SERVER_SUPPORT. - Everywhere: wrap all references to CVS_Username in #ifdef - AUTH_SERVER_SUPPORT. - - * cvs.h (Pserver_Repos): new var, used in consistency [security] - check. Defined only #ifdef AUTH_SERVER_SUPPORT. - (CVSROOTADM_PASSWD): new #define, trying to get with the program. - -Fri Jan 3 18:10:39 1997 Ian Lance Taylor <ian@cygnus.com> - - * checkout.c (build_dirs_and_chdir): Move call to Subdir_Register - until after we know that the directory exists. - -Thu Jan 2 13:30:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in, cvsbug.sh, edit.c, edit.h, error.c, error.h, - fileattr.c, fileattr.h, filesubr.c, run.c, update.h, watch.c, - watch.h: Remove "675" paragraph; see ../ChangeLog for rationale. - -Thu Jan 2 12:27:46 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh (info): New test info-cleanup-verifymsg gets rid of - verifymsg when we are done with it. - - * sanity.sh (basicb): Skip tests basicb-1a and basicb-9a for remote. - * sanity.sh (modules-155a4): It is OK if a CVS directory exists. - * sanity.sh (ignore): Do everything inside a "1" directory. The - change to create CVS directories at top-level causes messages such as - "? home" otherwise. In test 191, specify -I CVS so that new CVS - directory is ignored. - * sanity.sh (crerepos): Manually remove CVS directory which had not - existed before. - -Thu Jan 2 09:06:20 1997 Karl Fogel <kfogel@ynu38.ynu.edu.cn> - - * server.c: Changes for pserver read-only repository access: - (check_command_legal_p): new func. Right now, just checks if - repository modification is permitted, and that only if pserver is - active. - (do_cvs_command): take new parameter `cmd_name', a string. All - callers changed. Pass it on to new func check_command_legal_p() - before executing the command. - (CVS_Username): new global, init to NULL. Used by - check_command_legal_p(), set in check_password(). - (check_password): set above new global CVS_Username; reorganized a - bit to facilitate this. - (check_repository_password): give *host_user_ptr permanent - storage iff success. - - * main.c: Changes for pserver read-only repository access: - (lookup_command_attribute): new func. - (main): use new func lookup_command_attribute() to establish if - CVS_CMD_IGNORE_ADMROOT and CVS_CMD_USES_WORK_DIR. - - * cvs.h: Changes for pserver read-only repository access: - (CVSROOTADM_READERS, CVSROOTADM_WRITERS): new #defines. - Prototype lookup_command_attribute(). - (CVS_CMD_IGNORE_ADMROOT, CVS_CMD_USES_WORK_DIR, - CVS_CMD_MODIFIES_REPOSITORY): new #defines for - lookup_command_attribute() and its callers. - -Wed Jan 1 19:50:38 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * options.h.in: Reword comment for TMPDIR_DFLT to make it clear - that this isn't specific to the pserver server. - - * modules.c (do_module): Give an error message if one tries to - specify -a together with another option. - * sanity.sh (modules2): New tests modules2-a* test for above fix. - - * sanity.sh (devcom): Add tests devcom-a-nonexist and - devcom-t-nonexist for "cvs watchers" on nonexistent argument. - -1997-01-01 Fred Fish <fnf@ninemoons.com> - - * run.c (piped_child, filter_stream_through_program): Actually - install these HAVE_VFORK patches that got missed. - (There was a log entry for these changes for 29 Nov 1996 but it - seems I accidentally forgot to actually check them in -kingdon). - -Wed Jan 1 18:32:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in: Add ChangeLog-96. - * ChangeLog-96: New file, contains former contents of ChangeLog. - * ChangeLog: Now just contains 1997 changes. - - -For older changes see ChangeLog-96. diff --git a/contrib/cvs/src/Makefile.am b/contrib/cvs/src/Makefile.am deleted file mode 100644 index 63e6b18..0000000 --- a/contrib/cvs/src/Makefile.am +++ /dev/null @@ -1,138 +0,0 @@ -## Process this file with automake to produce Makefile.in -# Makefile for GNU CVS program. -# -# Copyright (C) 1986-2005 The Free Software Foundation, Inc. -# -# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, -# and others. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -SHELL = /bin/sh - -# $(includeopt) is CVS specific and set by configure -# FIXME - This includes line is dependant on its order. This means there is -# some namespace hackery going on that maybe shouldn't be. Long term fix is to -# try and remove naming ocnflicts and fix Automake to allow particular includes -# to be attached only to particular object files. Short term fix is either or. -##INCLUDES = -I. -I.. -I$(srcdir) -I$(top_srcdir)/lib -INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/diff -I$(top_srcdir)/zlib $(includeopt) - -bin_PROGRAMS = cvs -bin_SCRIPTS = cvsbug - -# The cvs executable -cvs_SOURCES = \ - add.c \ - admin.c \ - annotate.c \ - buffer.c \ - checkin.c \ - checkout.c \ - classify.c \ - client.c \ - commit.c \ - create_adm.c \ - cvsrc.c diff.c \ - edit.c \ - entries.c \ - error.c \ - expand_path.c \ - fileattr.c \ - filesubr.c \ - find_names.c \ - hardlink.c \ - hash.c \ - history.c \ - ignore.c \ - import.c \ - lock.c \ - log.c \ - login.c \ - logmsg.c \ - main.c \ - mkmodules.c \ - modules.c \ - myndbm.c \ - no_diff.c \ - parseinfo.c \ - patch.c \ - rcs.c \ - rcscmds.c \ - recurse.c \ - release.c \ - remove.c \ - repos.c \ - root.c \ - run.c \ - scramble.c \ - server.c \ - stack.c \ - status.c \ - subr.c \ - tag.c \ - update.c \ - version.c \ - vers_ts.c \ - watch.c \ - wrapper.c \ - zlib.c \ - buffer.h \ - client.h \ - cvs.h \ - edit.h \ - error.h \ - fileattr.h \ - hardlink.h \ - hash.h \ - history.h \ - myndbm.h \ - rcs.h \ - root.h \ - server.h \ - stack.h \ - update.h \ - watch.h - -cvs_LDADD = \ - ../diff/libdiff.a \ - ../lib/libcvs.a \ - ../zlib/libz.a - -# extra clean targets -# wish this could be distclean-hdr-local but it's not part of automake -DISTCLEANFILES = check.log check.plog - -# General -EXTRA_DIST = \ - .cvsignore \ - ChangeLog-9194 \ - ChangeLog-9395 \ - ChangeLog-96 \ - ChangeLog-97 \ - build_src.com \ - sanity.sh - -check-local: localcheck remotecheck - -.PHONY: localcheck -localcheck: - $(SHELL) $(srcdir)/sanity.sh `pwd`/cvs$(EXEEXT) - -.PHONY: remotecheck -remotecheck: all - $(SHELL) $(srcdir)/sanity.sh -r `pwd`/cvs$(EXEEXT) - -## MAINTAINER Targets - -# for backwards compatibility with the old makefiles -.PHONY: realclean -realclean: maintainer-clean diff --git a/contrib/cvs/src/Makefile.in b/contrib/cvs/src/Makefile.in deleted file mode 100644 index d88773c..0000000 --- a/contrib/cvs/src/Makefile.in +++ /dev/null @@ -1,658 +0,0 @@ -# Makefile.in generated by automake 1.10 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# Makefile for GNU CVS program. -# -# Copyright (C) 1986-2005 The Free Software Foundation, Inc. -# -# Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, -# and others. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -bin_PROGRAMS = cvs$(EXEEXT) -subdir = src -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ - $(srcdir)/cvsbug.in ChangeLog -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ - $(top_srcdir)/configure.in -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = cvsbug -am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" -binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) -PROGRAMS = $(bin_PROGRAMS) -am_cvs_OBJECTS = add.$(OBJEXT) admin.$(OBJEXT) annotate.$(OBJEXT) \ - buffer.$(OBJEXT) checkin.$(OBJEXT) checkout.$(OBJEXT) \ - classify.$(OBJEXT) client.$(OBJEXT) commit.$(OBJEXT) \ - create_adm.$(OBJEXT) cvsrc.$(OBJEXT) diff.$(OBJEXT) \ - edit.$(OBJEXT) entries.$(OBJEXT) error.$(OBJEXT) \ - expand_path.$(OBJEXT) fileattr.$(OBJEXT) filesubr.$(OBJEXT) \ - find_names.$(OBJEXT) hardlink.$(OBJEXT) hash.$(OBJEXT) \ - history.$(OBJEXT) ignore.$(OBJEXT) import.$(OBJEXT) \ - lock.$(OBJEXT) log.$(OBJEXT) login.$(OBJEXT) logmsg.$(OBJEXT) \ - main.$(OBJEXT) mkmodules.$(OBJEXT) modules.$(OBJEXT) \ - myndbm.$(OBJEXT) no_diff.$(OBJEXT) parseinfo.$(OBJEXT) \ - patch.$(OBJEXT) rcs.$(OBJEXT) rcscmds.$(OBJEXT) \ - recurse.$(OBJEXT) release.$(OBJEXT) remove.$(OBJEXT) \ - repos.$(OBJEXT) root.$(OBJEXT) run.$(OBJEXT) \ - scramble.$(OBJEXT) server.$(OBJEXT) stack.$(OBJEXT) \ - status.$(OBJEXT) subr.$(OBJEXT) tag.$(OBJEXT) update.$(OBJEXT) \ - version.$(OBJEXT) vers_ts.$(OBJEXT) watch.$(OBJEXT) \ - wrapper.$(OBJEXT) zlib.$(OBJEXT) -cvs_OBJECTS = $(am_cvs_OBJECTS) -cvs_DEPENDENCIES = ../diff/libdiff.a ../lib/libcvs.a ../zlib/libz.a -binSCRIPT_INSTALL = $(INSTALL_SCRIPT) -SCRIPTS = $(bin_SCRIPTS) -DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -SOURCES = $(cvs_SOURCES) -DIST_SOURCES = $(cvs_SOURCES) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CSH = @CSH@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EDITOR = @EDITOR@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -KRB4 = @KRB4@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAINT = @MAINT@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -MKTEMP = @MKTEMP@ -OBJEXT = @OBJEXT@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PERL = @PERL@ -PR = @PR@ -PS2PDF = @PS2PDF@ -RANLIB = @RANLIB@ -ROFF = @ROFF@ -SENDMAIL = @SENDMAIL@ -SET_MAKE = @SET_MAKE@ -SHELL = /bin/sh -STRIP = @STRIP@ -TEXI2DVI = @TEXI2DVI@ -VERSION = @VERSION@ -YACC = @YACC@ -YFLAGS = @YFLAGS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_prefix_program = @ac_prefix_program@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build_alias = @build_alias@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host_alias = @host_alias@ -htmldir = @htmldir@ -includedir = @includedir@ -includeopt = @includeopt@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -with_default_rsh = @with_default_rsh@ -with_default_ssh = @with_default_ssh@ - -# $(includeopt) is CVS specific and set by configure -# FIXME - This includes line is dependant on its order. This means there is -# some namespace hackery going on that maybe shouldn't be. Long term fix is to -# try and remove naming ocnflicts and fix Automake to allow particular includes -# to be attached only to particular object files. Short term fix is either or. -INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/diff -I$(top_srcdir)/zlib $(includeopt) -bin_SCRIPTS = cvsbug - -# The cvs executable -cvs_SOURCES = \ - add.c \ - admin.c \ - annotate.c \ - buffer.c \ - checkin.c \ - checkout.c \ - classify.c \ - client.c \ - commit.c \ - create_adm.c \ - cvsrc.c diff.c \ - edit.c \ - entries.c \ - error.c \ - expand_path.c \ - fileattr.c \ - filesubr.c \ - find_names.c \ - hardlink.c \ - hash.c \ - history.c \ - ignore.c \ - import.c \ - lock.c \ - log.c \ - login.c \ - logmsg.c \ - main.c \ - mkmodules.c \ - modules.c \ - myndbm.c \ - no_diff.c \ - parseinfo.c \ - patch.c \ - rcs.c \ - rcscmds.c \ - recurse.c \ - release.c \ - remove.c \ - repos.c \ - root.c \ - run.c \ - scramble.c \ - server.c \ - stack.c \ - status.c \ - subr.c \ - tag.c \ - update.c \ - version.c \ - vers_ts.c \ - watch.c \ - wrapper.c \ - zlib.c \ - buffer.h \ - client.h \ - cvs.h \ - edit.h \ - error.h \ - fileattr.h \ - hardlink.h \ - hash.h \ - history.h \ - myndbm.h \ - rcs.h \ - root.h \ - server.h \ - stack.h \ - update.h \ - watch.h - -cvs_LDADD = \ - ../diff/libdiff.a \ - ../lib/libcvs.a \ - ../zlib/libz.a - - -# extra clean targets -# wish this could be distclean-hdr-local but it's not part of automake -DISTCLEANFILES = check.log check.plog - -# General -EXTRA_DIST = \ - .cvsignore \ - ChangeLog-9194 \ - ChangeLog-9395 \ - ChangeLog-96 \ - ChangeLog-97 \ - build_src.com \ - sanity.sh - -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -cvsbug: $(top_builddir)/config.status $(srcdir)/cvsbug.in - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ -install-binPROGRAMS: $(bin_PROGRAMS) - @$(NORMAL_INSTALL) - test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - if test -f $$p \ - ; then \ - f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ - $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ - else :; fi; \ - done - -uninstall-binPROGRAMS: - @$(NORMAL_UNINSTALL) - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ - rm -f "$(DESTDIR)$(bindir)/$$f"; \ - done - -clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) -cvs$(EXEEXT): $(cvs_OBJECTS) $(cvs_DEPENDENCIES) - @rm -f cvs$(EXEEXT) - $(LINK) $(cvs_OBJECTS) $(cvs_LDADD) $(LIBS) -install-binSCRIPTS: $(bin_SCRIPTS) - @$(NORMAL_INSTALL) - test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" - @list='$(bin_SCRIPTS)'; for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - if test -f $$d$$p; then \ - f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ - echo " $(binSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(bindir)/$$f'"; \ - $(binSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(bindir)/$$f"; \ - else :; fi; \ - done - -uninstall-binSCRIPTS: - @$(NORMAL_UNINSTALL) - @list='$(bin_SCRIPTS)'; for p in $$list; do \ - f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ - echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ - rm -f "$(DESTDIR)$(bindir)/$$f"; \ - done - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/add.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/admin.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/annotate.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checkin.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checkout.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/classify.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commit.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/create_adm.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cvsrc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diff.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edit.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/entries.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expand_path.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileattr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filesubr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/find_names.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hardlink.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/history.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ignore.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/import.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/login.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logmsg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkmodules.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modules.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/myndbm.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/no_diff.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parseinfo.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/patch.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcscmds.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recurse.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/release.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remove.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repos.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/root.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scramble.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stack.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tag.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vers_ts.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watch.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrapper.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zlib.Po@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ - fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ - else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ - || exit 1; \ - fi; \ - done -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) check-local -check: check-am -all-am: Makefile $(PROGRAMS) $(SCRIPTS) -installdirs: - for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-binPROGRAMS clean-generic mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-exec-am: install-binPROGRAMS install-binSCRIPTS - -install-html: install-html-am - -install-info: install-info-am - -install-man: - -install-pdf: install-pdf-am - -install-ps: install-ps-am - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS all all-am check check-am check-local clean \ - clean-binPROGRAMS clean-generic ctags distclean \ - distclean-compile distclean-generic distclean-tags distdir dvi \ - dvi-am html html-am info info-am install install-am \ - install-binPROGRAMS install-binSCRIPTS install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ - uninstall-am uninstall-binPROGRAMS uninstall-binSCRIPTS - - -check-local: localcheck remotecheck - -.PHONY: localcheck -localcheck: - $(SHELL) $(srcdir)/sanity.sh `pwd`/cvs$(EXEEXT) - -.PHONY: remotecheck -remotecheck: all - $(SHELL) $(srcdir)/sanity.sh -r `pwd`/cvs$(EXEEXT) - -# for backwards compatibility with the old makefiles -.PHONY: realclean -realclean: maintainer-clean -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/contrib/cvs/src/add.c b/contrib/cvs/src/add.c deleted file mode 100644 index 228ae69..0000000 --- a/contrib/cvs/src/add.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (c) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (c) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Add - * - * Adds a file or directory to the RCS source repository. For a file, - * the entry is marked as "needing to be added" in the user's own CVS - * directory, and really added to the repository when it is committed. - * For a directory, it is added at the appropriate place in the source - * repository and a CVS directory is generated within the directory. - * - * The -m option is currently the only supported option. Some may wish to - * supply standard "rcs" options here, but I've found that this causes more - * trouble than anything else. - * - * The user files or directories must already exist. For a directory, it must - * not already have a CVS file in it. - * - * An "add" on a file that has been "remove"d but not committed will cause the - * file to be resurrected. - */ - -#include <assert.h> -#include "cvs.h" -#include "savecwd.h" -#include "fileattr.h" - -static int add_directory PROTO ((struct file_info *finfo)); -static int build_entry PROTO((const char *repository, const char *user, - const char *options, const char *message, - List * entries, const char *tag)); - -static const char *const add_usage[] = -{ - "Usage: %s %s [-k rcs-kflag] [-m message] files...\n", - "\t-k rcs-kflag\tUse \"rcs-kflag\" to add the file with the specified\n", - "\t\t\tkflag.\n", - "\t-m message\tUse \"message\" for the creation log.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -int -add (argc, argv) - int argc; - char **argv; -{ - char *message = NULL; - int i; - char *repository; - int c; - int err = 0; - int added_files = 0; - char *options = NULL; - List *entries; - Vers_TS *vers; - struct saved_cwd cwd; - /* 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); - - wrap_setup (); - - /* parse args */ - optind = 0; - while ((c = getopt (argc, argv, "+k:m:")) != -1) - { - switch (c) - { - case 'k': - if (options) free (options); - options = RCS_check_kflag (optarg); - break; - - case 'm': - if (message) free (message); - message = xstrdup (optarg); - break; - case '?': - default: - usage (add_usage); - break; - } - } - argc -= optind; - argv += optind; - - if (argc <= 0) - usage (add_usage); - - cvsroot_len = strlen (current_parsed_root->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. */ - for (i = 0; i < argc; i++) - { - int skip_file = 0; - - /* If it were up to me I'd probably make this a fatal error. - But some people are really fond of their "cvs add *", and - don't seem to object to the warnings. - Whatever. */ - strip_trailing_slashes (argv[i]); - if (strcmp (argv[i], ".") == 0 - || strcmp (argv[i], "..") == 0 - || fncmp (last_component(argv[i]), CVSADM) == 0) - { - if (!quiet) - error (0, 0, "cannot add special file `%s'; skipping", argv[i]); - skip_file = 1; - } - else - { - char *p; - p = argv[i]; - while (*p != '\0') - { - if (ISDIRSEP (*p)) - { - found_slash = 1; - break; - } - ++p; - } - } - - if (skip_file) - { - int j; - - /* FIXME: We don't do anything about free'ing argv[i]. But - the problem is that it is only sometimes allocated (see - cvsrc.c). */ - - for (j = i; j < argc - 1; ++j) - argv[j] = argv[j + 1]; - --argc; - /* Check the new argv[i] again. */ - --i; - ++err; - } - } - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - int j; - - if (argc == 0) - { - /* We snipped out all the arguments in the above sanity - check. We can just forget the whole thing (and we - better, because if we fired up the server and passed it - nothing, it would spit back a usage message). */ - if (options) - free (options); - if (message) - free (message); - return err; - } - - start_server (); - ign_setup (); - if (options) - { - send_arg (options); - free (options); - } - option_with_arg ("-m", message); - send_arg ("--"); - - /* If !found_slash, refrain from sending "Directory", for - CVS 1.9 compatibility. If we only tried to deal with servers - which are at least CVS 1.9.26 or so, we wouldn't have to - special-case this. */ - if (found_slash) - { - repository = Name_Repository (NULL, NULL); - send_a_repository ("", repository, ""); - free (repository); - } - - for (j = 0; j < argc; ++j) - { - /* FIXME: Does this erroneously call Create_Admin in error - conditions which are only detected once the server gets its - hands on things? */ - if (isdir (argv[j])) - { - char *tag; - char *date; - int nonbranch; - char *rcsdir; - char *p; - char *update_dir; - /* This is some mungeable storage into which we can point - with p and/or update_dir. */ - char *filedir; - - if (save_cwd (&cwd)) - error_exit (); - - filedir = xstrdup (argv[j]); - /* Deliberately discard the const below since we know we just - * allocated filedir and can do what we like with it. - */ - p = (char *)last_component (filedir); - if (p == filedir) - { - update_dir = ""; - } - else - { - p[-1] = '\0'; - update_dir = filedir; - if (CVS_CHDIR (update_dir) < 0) - error (1, errno, - "could not chdir to %s", update_dir); - } - - /* find the repository associated with our current dir */ - repository = Name_Repository (NULL, update_dir); - - /* don't add stuff to Emptydir */ - if (strncmp (repository, current_parsed_root->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); - - rcsdir = xmalloc (strlen (repository) + strlen (p) + 5); - sprintf (rcsdir, "%s/%s", repository, p); - - Create_Admin (p, argv[j], rcsdir, tag, date, - nonbranch, 0, 1); - - if (found_slash) - send_a_repository ("", repository, update_dir); - - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - - if (tag) - free (tag); - if (date) - free (date); - free (rcsdir); - - if (p == filedir) - Subdir_Register ((List *) NULL, (char *) NULL, argv[j]); - else - { - Subdir_Register ((List *) NULL, update_dir, p); - } - free (repository); - free (filedir); - } - } - send_files (argc, argv, 0, 0, SEND_BUILD_DIRS | SEND_NO_CONTENTS); - send_file_names (argc, argv, SEND_EXPAND_WILD); - send_to_server ("add\012", 0); - if (message) - free (message); - return err + get_responses_and_close (); - } -#endif - - /* walk the arg list adding files/dirs */ - for (i = 0; i < argc; i++) - { - int begin_err = err; -#ifdef SERVER_SUPPORT - int begin_added_files = added_files; -#endif - struct file_info finfo; - char *filename, *p; - - memset (&finfo, 0, sizeof finfo); - - if (save_cwd (&cwd)) - error_exit (); - - finfo.fullname = xstrdup (argv[i]); - filename = xstrdup (argv[i]); - /* We know we can discard the const below since we just allocated - * filename and can do as we like with it. - */ - p = (char *)last_component (filename); - if (p == filename) - { - finfo.update_dir = ""; - finfo.file = p; - } - else - { - p[-1] = '\0'; - finfo.update_dir = filename; - finfo.file = p; - if (CVS_CHDIR (finfo.update_dir) < 0) - error (1, errno, "could not chdir to %s", finfo.update_dir); - } - - /* Add wrappers for this directory. They exist only until - the next call to wrap_add_file. */ - wrap_add_file (CVSDOTWRAPPER, 1); - - finfo.rcs = NULL; - - /* Find the repository associated with our current dir. */ - repository = Name_Repository (NULL, finfo.update_dir); - - /* don't add stuff to Emptydir */ - if (strncmp (repository, current_parsed_root->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; - finfo.entries = entries; - - /* We pass force_tag_match as 1. If the directory has a - sticky branch tag, and there is already an RCS file which - does not have that tag, then the head revision is - meaningless to us. */ - vers = Version_TS (&finfo, options, NULL, NULL, 1, 0); - - if (vers->vn_user == NULL) - { - /* No entry available, ts_rcs is invalid */ - if (vers->vn_rcs == NULL) - { - /* There is no RCS file either */ - if (vers->ts_user == NULL) - { - /* There is no user file either */ - error (0, 0, "nothing known about %s", finfo.fullname); - err++; - } - else if (!isdir (finfo.file) - || wrap_name_has (finfo.file, WRAP_TOCVS)) - { - /* - * See if a directory exists in the repository with - * the same name. If so, blow this request off. - */ - char *dname = xmalloc (strlen (repository) - + strlen (finfo.file) - + 10); - (void) sprintf (dname, "%s/%s", repository, finfo.file); - if (isdir (dname)) - { - error (0, 0, - "cannot add file `%s' since the directory", - finfo.fullname); - error (0, 0, "`%s' already exists in the repository", - dname); - error (1, 0, "illegal filename overlap"); - } - free (dname); - - if (vers->options == NULL || *vers->options == '\0') - { - /* No options specified on command line (or in - rcs file if it existed, e.g. the file exists - on another branch). Check for a value from - the wrapper stuff. */ - if (wrap_name_has (finfo.file, WRAP_RCSOPTION)) - { - if (vers->options) - free (vers->options); - vers->options = wrap_rcsoption (finfo.file, 1); - } - } - - if (vers->nonbranch) - { - error (0, 0, - "cannot add file on non-branch tag %s", - vers->tag); - ++err; - } - else - { - /* There is a user file, so build the entry for it */ - if (build_entry (repository, finfo.file, vers->options, - message, entries, vers->tag) != 0) - err++; - else - { - added_files++; - if (!quiet) - { - if (vers->tag) - error (0, 0, "\ -scheduling %s `%s' for addition on branch `%s'", - (wrap_name_has (finfo.file, - WRAP_TOCVS) - ? "wrapper" - : "file"), - finfo.fullname, vers->tag); - else - error (0, 0, - "scheduling %s `%s' for addition", - (wrap_name_has (finfo.file, - WRAP_TOCVS) - ? "wrapper" - : "file"), - finfo.fullname); - } - } - } - } - } - else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) - { - if (isdir (finfo.file) - && !wrap_name_has (finfo.file, WRAP_TOCVS)) - { - error (0, 0, "\ -the directory `%s' cannot be added because a file of the", finfo.fullname); - error (1, 0, "\ -same name already exists in the repository."); - } - else - { - if (vers->nonbranch) - { - error (0, 0, - "cannot add file on non-branch tag %s", - vers->tag); - ++err; - } - else - { - char *timestamp = NULL; - if (vers->ts_user == NULL) - { - /* If this file does not exist locally, assume that - * the last version on the branch is being - * resurrected. - * - * Compute previous revision. We assume that it - * exists and that it is not a revision on the - * trunk of the form X.1 (1.1, 2.1, 3.1, ...). We - * also assume that it is not dead, which seems - * fair since we know vers->vn_rcs is dead - * and we shouldn't see two dead revisions in a - * row. - */ - char *prev = previous_rev (vers->srcfile, - vers->vn_rcs); - int status; - if (prev == NULL) - { - /* There is no previous revision. Either: - * - * * Revision 1.1 was dead, as when a file was - * inititially added on a branch, - * - * or - * - * * All previous revisions have been deleted. - * For instance, via `admin -o'. - */ - if (!really_quiet) - error (0, 0, -"File `%s' has no previous revision to resurrect.", - finfo.fullname); - free (prev); - goto skip_this_file; - } - if (!quiet) - error (0, 0, -"Resurrecting file `%s' from revision %s.", - finfo.fullname, prev); - status = RCS_checkout (vers->srcfile, finfo.file, - prev, vers->tag, - vers->options, RUN_TTY, - NULL, NULL); - xchmod (finfo.file, 1); - if (status != 0) - { - error (0, 0, "Failed to resurrect revision %s", - prev); - err++; - } - else - { - /* I don't actually set vers->ts_user here - * because it would confuse server_update(). - */ - timestamp = time_stamp (finfo.file); - if (!really_quiet) - write_letter (&finfo, 'U'); - } - free (prev); - } - if (!quiet) - { - if (vers->tag) - error (0, 0, -"file `%s' will be added on branch `%s' from version %s", - finfo.fullname, vers->tag, - vers->vn_rcs); - else - /* I'm not sure that mentioning - vers->vn_rcs makes any sense here; I - can't think of a way to word the - message which is not confusing. */ - error (0, 0, -"Re-adding file `%s' (in place of dead revision %s).", - finfo.fullname, vers->vn_rcs); - } - Register (entries, finfo.file, "0", - timestamp ? timestamp : vers->ts_user, - vers->options, vers->tag, vers->date, NULL); - if (timestamp) free (timestamp); -#ifdef SERVER_SUPPORT - if (server_active && vers->ts_user == NULL) - { - /* If we resurrected the file from the archive, we - * need to tell the client about it. - */ - server_updated (&finfo, vers, - SERVER_UPDATED, - (mode_t) -1, NULL, NULL); - /* This is kinda hacky or, at least, it renders the - * name "begin_added_files" obsolete, but we want - * the added_files to be counted without triggering - * the check that causes server_checked_in() to be - * called below since we have already called - * server_updated() to complete the resurrection. - */ - ++begin_added_files; - } -#endif - ++added_files; - } - } - } - else - { - /* - * There is an RCS file already, so somebody else must've - * added it - */ - error (0, 0, "%s added independently by second party", - finfo.fullname); - err++; - } - } - else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') - { - - /* - * An entry for a new-born file, ts_rcs is dummy, but that is - * inappropriate here - */ - if (!quiet) - error (0, 0, "%s has already been entered", finfo.fullname); - err++; - } - else if (vers->vn_user[0] == '-') - { - /* An entry for a removed file, ts_rcs is invalid */ - if (vers->ts_user == NULL) - { - /* There is no user file (as it should be) */ - if (vers->vn_rcs == NULL) - { - - /* - * There is no RCS file, so somebody else must've removed - * it from under us - */ - error (0, 0, "\ -cannot resurrect %s; RCS file removed by second party", finfo.fullname); - err++; - } - else - { - int status; - /* - * There is an RCS file, so remove the "-" from the - * version number and restore the file - */ - char *tmp = xmalloc (strlen (vers->vn_user)); - (void) strcpy (tmp, vers->vn_user + 1); - (void) strcpy (vers->vn_user, tmp); - free(tmp); - status = RCS_checkout (vers->srcfile, finfo.file, - vers->vn_user, vers->tag, - vers->options, RUN_TTY, - NULL, NULL); - xchmod (finfo.file, 1); - if (status != 0) - { - error (0, 0, "Failed to resurrect revision %s", - vers->vn_user); - err++; - tmp = NULL; - } - else - { - /* I don't actually set vers->ts_user here because it - * would confuse server_update(). - */ - tmp = time_stamp (finfo.file); - write_letter (&finfo, 'U'); - if (!quiet) - error (0, 0, "%s, version %s, resurrected", - finfo.fullname, vers->vn_user); - } - Register (entries, finfo.file, vers->vn_user, - tmp, vers->options, - vers->tag, vers->date, NULL); - if (tmp) free (tmp); -#ifdef SERVER_SUPPORT - if (server_active) - { - /* If we resurrected the file from the archive, we - * need to tell the client about it. - */ - server_updated (&finfo, vers, - SERVER_UPDATED, - (mode_t) -1, NULL, NULL); - } - /* We don't increment added_files here because this isn't - * a change that needs to be committed. - */ -#endif - } - } - else - { - /* The user file shouldn't be there */ - error (0, 0, "\ -%s should be removed and is still there (or is back again)", finfo.fullname); - err++; - } - } - else - { - /* A normal entry, ts_rcs is valid, so it must already be there */ - if (!quiet) - error (0, 0, "%s already exists, with version number %s", - finfo.fullname, - vers->vn_user); - err++; - } - freevers_ts (&vers); - - /* passed all the checks. Go ahead and add it if its a directory */ - if (begin_err == err - && isdir (finfo.file) - && !wrap_name_has (finfo.file, WRAP_TOCVS)) - { - err += add_directory (&finfo); - } - else - { -#ifdef SERVER_SUPPORT - if (server_active && begin_added_files != added_files) - server_checked_in (finfo.file, finfo.update_dir, repository); -#endif - } - -skip_this_file: - free (repository); - Entries_Close (entries); - - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - - /* It's okay to discard the const to free this - we allocated this - * above. The const is for everybody else. - */ - free ((char *) finfo.fullname); - free ((char *) filename); - } - if (added_files && !really_quiet) - error (0, 0, "use '%s commit' to add %s permanently", - program_name, - (added_files == 1) ? "this file" : "these files"); - - if (message) - free (message); - if (options) - free (options); - - return err; -} - - - -/* - * The specified user file is really a directory. So, let's make sure that - * it is created in the RCS source repository, and that the user's directory - * is updated to include a CVS directory. - * - * Returns 1 on failure, 0 on success. - */ -static int -add_directory (finfo) - struct file_info *finfo; -{ - const char *repository = finfo->repository; - List *entries = finfo->entries; - const char *dir = finfo->file; - - char *rcsdir = NULL; - struct saved_cwd cwd; - char *message = NULL; - char *tag, *date; - int nonbranch; - char *attrs; - - if (strchr (dir, '/') != NULL) - { - /* "Can't happen". */ - error (0, 0, - "directory %s not added; must be a direct sub-directory", dir); - return 1; - } - if (fncmp (dir, CVSADM) == 0) - { - error (0, 0, "cannot add a `%s' directory", CVSADM); - return 1; - } - - /* before we do anything else, see if we have any per-directory tags */ - ParseTag (&tag, &date, &nonbranch); - - /* Remember the default attributes from this directory, so we can apply - them to the new directory. */ - fileattr_startdir (repository); - attrs = fileattr_getall (NULL); - fileattr_free (); - - /* now, remember where we were, so we can get back */ - if (save_cwd (&cwd)) - return 1; - if (CVS_CHDIR (dir) < 0) - { - error (0, errno, "cannot chdir to %s", finfo->fullname); - return 1; - } - if (!server_active && isfile (CVSADM)) - { - error (0, 0, "%s/%s already exists", finfo->fullname, CVSADM); - goto out; - } - - rcsdir = xmalloc (strlen (repository) + strlen (dir) + 5); - sprintf (rcsdir, "%s/%s", repository, dir); - if (isfile (rcsdir) && !isdir (rcsdir)) - { - error (0, 0, "%s is not a directory; %s not added", rcsdir, - finfo->fullname); - goto out; - } - - /* setup the log message */ - message = xmalloc (strlen (rcsdir) - + 80 - + (tag == NULL ? 0 : strlen (tag) + 80) - + (date == NULL ? 0 : strlen (date) + 80)); - (void) sprintf (message, "Directory %s added to the repository\n", - rcsdir); - if (tag) - { - (void) strcat (message, "--> Using per-directory sticky tag `"); - (void) strcat (message, tag); - (void) strcat (message, "'\n"); - } - if (date) - { - (void) strcat (message, "--> Using per-directory sticky date `"); - (void) strcat (message, date); - (void) strcat (message, "'\n"); - } - - if (!isdir (rcsdir)) - { - mode_t omask; - Node *p; - List *ulist; - struct logfile_info *li; - - /* There used to be some code here which would prompt for - whether to add the directory. The details of that code had - bitrotted, but more to the point it can't work - client/server, doesn't ask in the right way for GUIs, etc. - A better way of making it harder to accidentally add - directories would be to have to add and commit directories - like for files. The code was #if 0'd at least since CVS 1.5. */ - - if (!noexec) - { - omask = umask (cvsumask); - if (CVS_MKDIR (rcsdir, 0777) < 0) - { - error (0, errno, "cannot mkdir %s", rcsdir); - (void) umask (omask); - goto out; - } - (void) umask (omask); - } - - /* Now set the default file attributes to the ones we inherited - from the parent directory. */ - fileattr_startdir (rcsdir); - fileattr_setall (NULL, attrs); - fileattr_write (); - fileattr_free (); - if (attrs != NULL) - { - free (attrs); - attrs = NULL; - } - - /* - * Set up an update list with a single title node for Update_Logfile - */ - ulist = getlist (); - p = getnode (); - p->type = UPDATE; - p->delproc = update_delproc; - p->key = xstrdup ("- New directory"); - li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info)); - li->type = T_TITLE; - li->tag = xstrdup (tag); - li->rev_old = li->rev_new = NULL; - p->data = li; - (void) addnode (ulist, p); - Update_Logfile (rcsdir, message, (FILE *) NULL, ulist); - dellist (&ulist); - } - - if (!server_active) - Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0, 1); - if (tag) - free (tag); - if (date) - free (date); - - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - - Subdir_Register (entries, (char *) NULL, dir); - - if (!really_quiet) - cvs_output (message, 0); - - free (rcsdir); - free (message); - if (attrs != NULL) - free (attrs); - - return 0; - -out: - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - if (message) free (message); - if (rcsdir != NULL) - free (rcsdir); - return 0; -} - - - -/* - * Builds an entry for a new file and sets up "CVS/file",[pt] by - * interrogating the user. Returns non-zero on error. - */ -static int -build_entry (repository, user, options, message, entries, tag) - const char *repository; - const char *user; - const char *options; - const char *message; - List *entries; - const char *tag; -{ - char *fname; - char *line; - FILE *fp; - - if (noexec) - return 0; - - /* - * The requested log is read directly from the user and stored in the - * file user,t. If the "message" argument is set, use it as the - * initial creation log (which typically describes the file). - */ - fname = xmalloc (strlen (user) + 80); - (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_LOG); - fp = open_file (fname, "w+"); - if (message && fputs (message, fp) == EOF) - error (1, errno, "cannot write to %s", fname); - if (fclose(fp) == EOF) - error(1, errno, "cannot close %s", fname); - free (fname); - - /* - * Create the entry now, since this allows the user to interrupt us above - * without needing to clean anything up (well, we could clean up the - * ,t file, but who cares). - */ - line = xmalloc (strlen (user) + 20); - (void) sprintf (line, "Initial %s", user); - Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0); - free (line); - return 0; -} diff --git a/contrib/cvs/src/admin.c b/contrib/cvs/src/admin.c deleted file mode 100644 index 186e27c..0000000 --- a/contrib/cvs/src/admin.c +++ /dev/null @@ -1,950 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (c) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (c) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Administration ("cvs admin") - * - */ - -#include "cvs.h" -#ifdef CVS_ADMIN_GROUP -#include <grp.h> -#endif -#include <assert.h> - -static Dtype admin_dirproc PROTO ((void *callerdat, const char *dir, - const char *repos, const char *update_dir, - List *entries)); -static int admin_fileproc PROTO ((void *callerdat, struct file_info *finfo)); - -static const char *const admin_usage[] = -{ - "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) Substitute keyword and value.\n", - "\t kvl Substitute keyword, value, and locker (if any).\n", - "\t k Substitute keyword only.\n", - "\t o Preserve original string.\n", - "\t b Like o, but mark file as binary.\n", - "\t v Substitute 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, including rev1 and rev2.\n", - "\t rev1::rev2 Between rev1 and rev2, excluding rev1 and rev2.\n", - "\t rev: rev and following revisions on the same branch.\n", - "\t rev:: After rev on the same branch.\n", - "\t :rev rev and previous revisions on the same branch.\n", - "\t ::rev Before rev on the same branch.\n", - "\t rev Just rev.\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 -}; - -/* This structure is used to pass information through start_recursion. */ -struct admin_data -{ - /* Set default branch (-b). It is "-b" followed by the value - given, or NULL if not specified, or merely "-b" if -b is - specified without a value. */ - char *branch; - - /* Set comment leader (-c). It is "-c" followed by the value - given, or NULL if not specified. The comment leader is - relevant only for old versions of RCS, but we let people set it - anyway. */ - char *comment; - - /* Set strict locking (-L). */ - int set_strict; - - /* Set nonstrict locking (-U). */ - int set_nonstrict; - - /* Delete revisions (-o). It is "-o" followed by the value specified. */ - char *delete_revs; - - /* Keyword substitution mode (-k), e.g. "-kb". */ - char *kflag; - - /* Description (-t). */ - char *desc; - - /* Interactive (-I). Problematic with client/server. */ - int interactive; - - /* This is the cheesy part. It is a vector with the options which - we don't deal with above (e.g. "-afoo" "-abar,baz"). In the future - this presumably will be replaced by other variables which break - out the data in a more convenient fashion. AV as well as each of - the strings it points to is malloc'd. */ - int ac; - char **av; - int av_alloc; -}; - -/* Add an argument. OPT is the option letter, e.g. 'a'. ARG is the - argument to that option, or NULL if omitted (whether NULL can actually - happen depends on whether the option was specified as optional to - getopt). */ -static void -arg_add (dat, opt, arg) - struct admin_data *dat; - int opt; - char *arg; -{ - char *newelt = xmalloc ((arg == NULL ? 0 : strlen (arg)) + 3); - strcpy (newelt, "-"); - newelt[1] = opt; - if (arg == NULL) - newelt[2] = '\0'; - else - strcpy (newelt + 2, arg); - - if (dat->av_alloc == 0) - { - dat->av_alloc = 1; - dat->av = (char **) xmalloc (dat->av_alloc * sizeof (*dat->av)); - } - else if (dat->ac >= dat->av_alloc) - { - dat->av_alloc *= 2; - dat->av = (char **) xrealloc (dat->av, - dat->av_alloc * sizeof (*dat->av)); - } - dat->av[dat->ac++] = newelt; -} - -int -admin (argc, argv) - int argc; - char **argv; -{ - int err; -#ifdef CVS_ADMIN_GROUP - struct group *grp; - struct group *getgrnam(); -#endif - struct admin_data admin_data; - int c; - int i; - int only_k_option; - - if (argc <= 1) - usage (admin_usage); - - wrap_setup (); - - memset (&admin_data, 0, sizeof admin_data); - - /* TODO: get rid of `-' switch notation in admin_data. For - example, admin_data->branch should be not `-bfoo' but simply `foo'. */ - - optind = 0; - only_k_option = 1; - while ((c = getopt (argc, argv, - "+ib::c:a:A:e::l::u::LUn:N:m:o:s:t::IqxV:k:")) != -1) - { - if (c != 'k' && c != 'q') - only_k_option = 0; - - switch (c) - { - case 'i': - /* This has always been documented as useless in cvs.texinfo - and it really is--admin_fileproc silently does nothing - if vers->vn_user is NULL. */ - error (0, 0, "the -i option to admin is not supported"); - error (0, 0, "run add or import to create an RCS file"); - goto usage_error; - - case 'b': - if (admin_data.branch != NULL) - { - error (0, 0, "duplicate 'b' option"); - goto usage_error; - } - if (optarg == NULL) - admin_data.branch = xstrdup ("-b"); - else - { - admin_data.branch = xmalloc (strlen (optarg) + 5); - strcpy (admin_data.branch, "-b"); - strcat (admin_data.branch, optarg); - } - break; - - case 'c': - if (admin_data.comment != NULL) - { - error (0, 0, "duplicate 'c' option"); - goto usage_error; - } - admin_data.comment = xmalloc (strlen (optarg) + 5); - strcpy (admin_data.comment, "-c"); - strcat (admin_data.comment, optarg); - break; - - case 'a': - arg_add (&admin_data, 'a', optarg); - break; - - case 'A': - /* In the client/server case, this is cheesy because - we just pass along the name of the RCS file, which - then will want to exist on the server. This is - accidental; having the client specify a pathname on - the server is not a design feature of the protocol. */ - arg_add (&admin_data, 'A', optarg); - break; - - case 'e': - arg_add (&admin_data, 'e', optarg); - break; - - case 'l': - /* Note that multiple -l options are legal. */ - arg_add (&admin_data, 'l', optarg); - break; - - case 'u': - /* Note that multiple -u options are legal. */ - arg_add (&admin_data, 'u', optarg); - break; - - case 'L': - /* Probably could also complain if -L is specified multiple - times, although RCS doesn't and I suppose it is reasonable - just to have it mean the same as a single -L. */ - if (admin_data.set_nonstrict) - { - error (0, 0, "-U and -L are incompatible"); - goto usage_error; - } - admin_data.set_strict = 1; - break; - - case 'U': - /* Probably could also complain if -U is specified multiple - times, although RCS doesn't and I suppose it is reasonable - just to have it mean the same as a single -U. */ - if (admin_data.set_strict) - { - error (0, 0, "-U and -L are incompatible"); - goto usage_error; - } - admin_data.set_nonstrict = 1; - break; - - case 'n': - /* Mostly similar to cvs tag. Could also be parsing - the syntax of optarg, although for now we just pass - it to rcs as-is. Note that multiple -n options are - legal. */ - arg_add (&admin_data, 'n', optarg); - break; - - case 'N': - /* Mostly similar to cvs tag. Could also be parsing - the syntax of optarg, although for now we just pass - it to rcs as-is. Note that multiple -N options are - legal. */ - arg_add (&admin_data, 'N', optarg); - break; - - case 'm': - /* Change log message. Could also be parsing the syntax - of optarg, although for now we just pass it to rcs - as-is. Note that multiple -m options are legal. */ - arg_add (&admin_data, 'm', optarg); - break; - - case 'o': - /* Delete revisions. Probably should also be parsing the - syntax of optarg, so that the client can give errors - rather than making the server take care of that. - Other than that I'm not sure whether it matters much - whether we parse it here or in admin_fileproc. - - Note that multiple -o options are illegal, in RCS - as well as here. */ - - if (admin_data.delete_revs != NULL) - { - error (0, 0, "duplicate '-o' option"); - goto usage_error; - } - admin_data.delete_revs = xmalloc (strlen (optarg) + 5); - strcpy (admin_data.delete_revs, "-o"); - strcat (admin_data.delete_revs, optarg); - break; - - case 's': - /* Note that multiple -s options are legal. */ - arg_add (&admin_data, 's', optarg); - break; - - case 't': - if (admin_data.desc != NULL) - { - error (0, 0, "duplicate 't' option"); - goto usage_error; - } - if (optarg != NULL && optarg[0] == '-') - admin_data.desc = xstrdup (optarg + 1); - else - { - size_t bufsize = 0; - size_t len; - - get_file (optarg, optarg, "r", &admin_data.desc, - &bufsize, &len); - } - break; - - case 'I': - /* At least in RCS this can be specified several times, - with the same meaning as being specified once. */ - admin_data.interactive = 1; - break; - - case 'q': - /* Silently set the global really_quiet flag. This keeps admin in - * sync with the RCS man page and allows us to silently support - * older servers when necessary. - * - * Some logic says we might want to output a deprecation warning - * here, but I'm opting not to in order to stay quietly in sync - * with the RCS man page. - */ - really_quiet = 1; - break; - - case 'x': - error (0, 0, "the -x option has never done anything useful"); - error (0, 0, "RCS files in CVS always end in ,v"); - goto usage_error; - - case 'V': - /* No longer supported. */ - error (0, 0, "the `-V' option is obsolete"); - break; - - case 'k': - if (admin_data.kflag != NULL) - { - error (0, 0, "duplicate '-k' option"); - goto usage_error; - } - admin_data.kflag = RCS_check_kflag (optarg); - break; - default: - case '?': - /* getopt will have printed an error message. */ - - usage_error: - /* Don't use cvs_cmd_name; it might be "server". */ - error (1, 0, "specify %s -H admin for usage information", - program_name); - } - } - argc -= optind; - argv += optind; - -#ifdef CVS_ADMIN_GROUP - /* The use of `cvs admin -k' is unrestricted. However, any other - option is restricted if the group CVS_ADMIN_GROUP exists on the - server. */ - /* This is only "secure" on the server, since the user could edit the - * RCS file on a local host, but some people like this kind of - * check anyhow. The alternative would be to check only when - * (server_active) rather than when not on the client. - */ - if (!current_parsed_root->isremote && !only_k_option && - (grp = getgrnam(CVS_ADMIN_GROUP)) != NULL) - { -#ifdef HAVE_GETGROUPS - gid_t *grps; - int n; - - /* get number of auxiliary groups */ - n = getgroups (0, NULL); - if (n < 0) - error (1, errno, "unable to get number of auxiliary groups"); - grps = (gid_t *) xmalloc((n + 1) * sizeof *grps); - n = getgroups (n, grps); - if (n < 0) - error (1, errno, "unable to get list of auxiliary groups"); - grps[n] = getgid(); - for (i = 0; i <= n; i++) - if (grps[i] == grp->gr_gid) break; - free (grps); - if (i > n) - error (1, 0, "usage is restricted to members of the group %s", - CVS_ADMIN_GROUP); -#else - char *me = getcaller(); - char **grnam; - - for (grnam = grp->gr_mem; *grnam; grnam++) - if (strcmp (*grnam, me) == 0) break; - if (!*grnam && getgid() != grp->gr_gid) - error (1, 0, "usage is restricted to members of the group %s", - CVS_ADMIN_GROUP); -#endif - } -#endif /* defined CVS_ADMIN_GROUP */ - - for (i = 0; i < admin_data.ac; ++i) - { - assert (admin_data.av[i][0] == '-'); - switch (admin_data.av[i][1]) - { - case 'm': - case 'l': - case 'u': - check_numeric (&admin_data.av[i][2], argc, argv); - break; - default: - break; - } - } - if (admin_data.branch != NULL) - check_numeric (admin_data.branch + 2, argc, argv); - if (admin_data.delete_revs != NULL) - { - char *p; - - check_numeric (admin_data.delete_revs + 2, argc, argv); - p = strchr (admin_data.delete_revs + 2, ':'); - if (p != NULL && isdigit ((unsigned char) p[1])) - check_numeric (p + 1, argc, argv); - else if (p != NULL && p[1] == ':' && isdigit ((unsigned char) p[2])) - check_numeric (p + 2, argc, argv); - } - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - /* Note that option_with_arg does not work for us, because some - of the options must be sent without a space between the option - and its argument. */ - if (admin_data.interactive) - error (1, 0, "-I option not useful with client/server"); - if (admin_data.branch != NULL) - send_arg (admin_data.branch); - if (admin_data.comment != NULL) - send_arg (admin_data.comment); - if (admin_data.set_strict) - send_arg ("-L"); - if (admin_data.set_nonstrict) - send_arg ("-U"); - if (admin_data.delete_revs != NULL) - send_arg (admin_data.delete_revs); - if (admin_data.desc != NULL) - { - 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); - } - /* Send this for all really_quiets since we know that it will be silently - * ignored when unneeded. This supports old servers. - */ - if (really_quiet) - send_arg ("-q"); - if (admin_data.kflag != NULL) - send_arg (admin_data.kflag); - - for (i = 0; i < admin_data.ac; ++i) - send_arg (admin_data.av[i]); - - send_arg ("--"); - send_files (argc, argv, 0, 0, SEND_NO_CONTENTS); - send_file_names (argc, argv, SEND_EXPAND_WILD); - send_to_server ("admin\012", 0); - err = get_responses_and_close (); - goto return_it; - } -#endif /* CLIENT_SUPPORT */ - - lock_tree_for_write (argc, argv, 0, W_LOCAL, 0); - - err = start_recursion (admin_fileproc, (FILESDONEPROC) NULL, admin_dirproc, - (DIRLEAVEPROC) NULL, (void *)&admin_data, - argc, argv, 0, - W_LOCAL, 0, CVS_LOCK_NONE, (char *) NULL, 1, - (char *) NULL); - Lock_Cleanup (); - - return_it: - if (admin_data.branch != NULL) - free (admin_data.branch); - if (admin_data.comment != NULL) - free (admin_data.comment); - if (admin_data.delete_revs != NULL) - free (admin_data.delete_revs); - if (admin_data.kflag != NULL) - free (admin_data.kflag); - if (admin_data.desc != NULL) - free (admin_data.desc); - for (i = 0; i < admin_data.ac; ++i) - free (admin_data.av[i]); - if (admin_data.av != NULL) - free (admin_data.av); - - return (err); -} - -/* - * Called to run "rcs" on a particular file. - */ -/* ARGSUSED */ -static int -admin_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - struct admin_data *admin_data = (struct admin_data *) callerdat; - Vers_TS *vers; - char *version; - int i; - int status = 0; - RCSNode *rcs, *rcs2; - - vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0); - - version = vers->vn_user; - if (version != NULL && strcmp (version, "0") == 0) - { - error (0, 0, "cannot admin newly added file `%s'", finfo->file); - status = 1; - goto exitfunc; - } - - rcs = vers->srcfile; - if (rcs == NULL) - { - if (!really_quiet) - error (0, 0, "nothing known about %s", finfo->file); - status = 1; - goto exitfunc; - } - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - if (!really_quiet) - { - cvs_output ("RCS file: ", 0); - cvs_output (rcs->path, 0); - cvs_output ("\n", 1); - } - - if (admin_data->branch != NULL) - { - char *branch = &admin_data->branch[2]; - if (*branch != '\0' && ! isdigit ((unsigned char) *branch)) - { - branch = RCS_whatbranch (rcs, admin_data->branch + 2); - if (branch == NULL) - { - error (0, 0, "%s: Symbolic name %s is undefined.", - rcs->path, admin_data->branch + 2); - status = 1; - } - } - if (status == 0) - RCS_setbranch (rcs, branch); - if (branch != NULL && branch != &admin_data->branch[2]) - free (branch); - } - if (admin_data->comment != NULL) - { - if (rcs->comment != NULL) - free (rcs->comment); - rcs->comment = xstrdup (admin_data->comment + 2); - } - if (admin_data->set_strict) - rcs->strict_locks = 1; - if (admin_data->set_nonstrict) - rcs->strict_locks = 0; - if (admin_data->delete_revs != NULL) - { - char *s, *t, *rev1, *rev2; - /* Set for :, clear for ::. */ - int inclusive; - char *t2; - - s = admin_data->delete_revs + 2; - inclusive = 1; - t = strchr (s, ':'); - if (t != NULL) - { - if (t[1] == ':') - { - inclusive = 0; - t2 = t + 2; - } - else - t2 = t + 1; - } - - /* Note that we don't support '-' for ranges. RCS considers it - obsolete and it is problematic with tags containing '-'. "cvs log" - has made the same decision. */ - - if (t == NULL) - { - /* -orev */ - rev1 = xstrdup (s); - rev2 = xstrdup (s); - } - else if (t == s) - { - /* -o:rev2 */ - rev1 = NULL; - rev2 = xstrdup (t2); - } - else - { - *t = '\0'; - rev1 = xstrdup (s); - *t = ':'; /* probably unnecessary */ - if (*t2 == '\0') - /* -orev1: */ - rev2 = NULL; - else - /* -orev1:rev2 */ - rev2 = xstrdup (t2); - } - - if (rev1 == NULL && rev2 == NULL) - { - /* RCS segfaults if `-o:' is given */ - error (0, 0, "no valid revisions specified in `%s' option", - admin_data->delete_revs); - status = 1; - } - else - { - status |= RCS_delete_revs (rcs, rev1, rev2, inclusive); - if (rev1) - free (rev1); - if (rev2) - free (rev2); - } - } - if (admin_data->desc != NULL) - { - free (rcs->desc); - rcs->desc = xstrdup (admin_data->desc); - } - if (admin_data->kflag != NULL) - { - char *kflag = admin_data->kflag + 2; - char *oldexpand = RCS_getexpand (rcs); - if (oldexpand == NULL || strcmp (oldexpand, kflag) != 0) - RCS_setexpand (rcs, kflag); - } - - /* Handle miscellaneous options. TODO: decide whether any or all - of these should have their own fields in the admin_data - structure. */ - for (i = 0; i < admin_data->ac; ++i) - { - char *arg; - char *p, *rev, *revnum, *tag, *msg; - char **users; - int argc, u; - Node *n; - RCSVers *delta; - - arg = admin_data->av[i]; - switch (arg[1]) - { - case 'a': /* fall through */ - case 'e': - line2argv (&argc, &users, arg + 2, " ,\t\n"); - 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]); - free_names (&argc, users); - break; - case 'A': - - /* See admin-19a-admin and friends in sanity.sh for - relative pathnames. It makes sense to think in - terms of a syntax which give pathnames relative to - the repository or repository corresponding to the - current directory or some such (and perhaps don't - include ,v), but trying to worry about such things - is a little pointless unless you first worry about - whether "cvs admin -A" as a whole makes any sense - (currently probably not, as access lists don't - affect the behavior of CVS). */ - - rcs2 = RCS_parsercsfile (arg + 2); - if (rcs2 == NULL) - error (1, 0, "cannot continue"); - - p = xstrdup (RCS_getaccess (rcs2)); - line2argv (&argc, &users, p, " \t\n"); - free (p); - freercsnode (&rcs2); - - for (u = 0; u < argc; ++u) - RCS_addaccess (rcs, users[u]); - free_names (&argc, users); - break; - case 'n': /* fall through */ - case 'N': - if (arg[2] == '\0') - { - cvs_outerr ("missing symbolic name after ", 0); - cvs_outerr (arg, 0); - cvs_outerr ("\n", 1); - break; - } - p = strchr (arg, ':'); - if (p == NULL) - { - if (RCS_deltag (rcs, arg + 2) != 0) - { - error (0, 0, "%s: Symbolic name %s is undefined.", - rcs->path, - arg + 2); - status = 1; - continue; - } - break; - } - *p = '\0'; - tag = xstrdup (arg + 2); - *p++ = ':'; - - /* Option `n' signals an error if this tag is already bound. */ - if (arg[1] == 'n') - { - n = findnode (RCS_symbols (rcs), tag); - if (n != NULL) - { - error (0, 0, - "%s: symbolic name %s already bound to %s", - rcs->path, - tag, (char *)n->data); - status = 1; - free (tag); - continue; - } - } - - /* Attempt to perform the requested tagging. */ - - if ((*p == 0 && (rev = RCS_head (rcs))) - || (rev = RCS_tag2rev (rcs, p))) /* tag2rev may exit */ - { - RCS_check_tag (tag); /* exit if not a valid tag */ - RCS_settag (rcs, tag, rev); - free (rev); - } - else - { - if (!really_quiet) - error (0, 0, - "%s: Symbolic name or revision %s is undefined.", - rcs->path, p); - status = 1; - } - free (tag); - break; - case 's': - p = strchr (arg, ':'); - if (p == NULL) - { - tag = xstrdup (arg + 2); - rev = RCS_head (rcs); - if (!rev) - { - error (0, 0, "No head revision in archive file `%s'.", - rcs->path); - status = 1; - continue; - } - } - else - { - *p = '\0'; - tag = xstrdup (arg + 2); - *p++ = ':'; - rev = xstrdup (p); - } - revnum = RCS_gettag (rcs, rev, 0, NULL); - if (revnum != NULL) - { - n = findnode (rcs->versions, revnum); - free (revnum); - } - else - n = NULL; - if (n == NULL) - { - error (0, 0, - "%s: can't set state of nonexisting revision %s", - rcs->path, - rev); - free (rev); - status = 1; - continue; - } - free (rev); - delta = n->data; - free (delta->state); - delta->state = tag; - break; - - case 'm': - p = strchr (arg, ':'); - if (p == NULL) - { - error (0, 0, "%s: -m option lacks revision number", - rcs->path); - status = 1; - continue; - } - *p = '\0'; /* temporarily make arg+2 its own string */ - rev = RCS_gettag (rcs, arg + 2, 1, NULL); /* Force tag match */ - if (rev == NULL) - { - error (0, 0, "%s: no such revision %s", rcs->path, arg+2); - status = 1; - *p = ':'; /* restore the full text of the -m argument */ - continue; - } - msg = p+1; - - n = findnode (rcs->versions, rev); - /* tags may exist against non-existing versions */ - if (n == NULL) - { - error (0, 0, "%s: no such revision %s: %s", - rcs->path, arg+2, rev); - status = 1; - *p = ':'; /* restore the full text of the -m argument */ - free (rev); - continue; - } - *p = ':'; /* restore the full text of the -m argument */ - free (rev); - - delta = n->data; - if (delta->text == NULL) - { - delta->text = (Deltatext *) xmalloc (sizeof (Deltatext)); - memset ((void *) delta->text, 0, sizeof (Deltatext)); - } - delta->text->version = xstrdup (delta->version); - delta->text->log = make_message_rcslegal (msg); - break; - - case 'l': - status |= RCS_lock (rcs, arg[2] ? arg + 2 : NULL, 0); - break; - case 'u': - status |= RCS_unlock (rcs, arg[2] ? arg + 2 : NULL, 0); - break; - default: assert(0); /* can't happen */ - } - } - - if (status == 0) - { - RCS_rewrite (rcs, NULL, NULL); - if (!really_quiet) - cvs_output ("done\n", 5); - } - else - { - /* Note that this message should only occur after another - message has given a more specific error. The point of this - additional message is to make it clear that the previous problems - caused CVS to forget about the idea of modifying the RCS file. */ - if (!really_quiet) - error (0, 0, "RCS file for `%s' not modified.", finfo->file); - RCS_abandon (rcs); - } - - exitfunc: - freevers_ts (&vers); - return status; -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -admin_dirproc (callerdat, dir, repos, update_dir, entries) - void *callerdat; - const char *dir; - const char *repos; - const char *update_dir; - List *entries; -{ - if (!quiet) - error (0, 0, "Administrating %s", update_dir); - return (R_PROCESS); -} diff --git a/contrib/cvs/src/annotate.c b/contrib/cvs/src/annotate.c deleted file mode 100644 index d6d0acc..0000000 --- a/contrib/cvs/src/annotate.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (c) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (c) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Show last revision where each line modified - * - * Prints the specified files with each line annotated with the revision - * number where it was last modified. With no argument, annotates all - * all the files in the directory (recursive by default). - */ - -#include "cvs.h" - -/* Options from the command line. */ - -static int force_tag_match = 1; -static int force_binary = 0; -static char *tag = NULL; -static int tag_validated; -static char *date = NULL; - -static int is_rannotate; - -static int annotate_fileproc PROTO ((void *callerdat, struct file_info *)); -static int rannotate_proc PROTO((int argc, char **argv, char *xwhere, - char *mwhere, char *mfile, int shorten, - int local, char *mname, char *msg)); - -static const char *const annotate_usage[] = -{ - "Usage: %s %s [-lRfF] [-r rev] [-D date] [files...]\n", - "\t-l\tLocal directory only, no recursion.\n", - "\t-R\tProcess directories recursively.\n", - "\t-f\tUse head revision if tag/date not found.\n", - "\t-F\tAnnotate binary files.\n", - "\t-r rev\tAnnotate file as of specified revision/tag.\n", - "\t-D date\tAnnotate file as of specified date.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -/* Command to show the revision, date, and author where each line of a - file was modified. */ - -int -annotate (argc, argv) - int argc; - char **argv; -{ - int local = 0; - int err = 0; - int c; - - is_rannotate = (strcmp(cvs_cmd_name, "rannotate") == 0); - - if (argc == -1) - usage (annotate_usage); - - optind = 0; - while ((c = getopt (argc, argv, "+lr:D:fFR")) != -1) - { - switch (c) - { - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'r': - tag = optarg; - break; - case 'D': - date = Make_Date (optarg); - break; - case 'f': - force_tag_match = 0; - break; - case 'F': - force_binary = 1; - break; - case '?': - default: - usage (annotate_usage); - break; - } - } - argc -= optind; - argv += optind; - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - start_server (); - - if (is_rannotate && !supported_request ("rannotate")) - error (1, 0, "server does not support rannotate"); - - ign_setup (); - - if (local) - send_arg ("-l"); - if (!force_tag_match) - send_arg ("-f"); - if (force_binary) - send_arg ("-F"); - option_with_arg ("-r", tag); - if (date) - client_senddate (date); - send_arg ("--"); - if (is_rannotate) - { - int i; - for (i = 0; i < argc; i++) - send_arg (argv[i]); - send_to_server ("rannotate\012", 0); - } - else - { - send_files (argc, argv, local, 0, SEND_NO_CONTENTS); - send_file_names (argc, argv, SEND_EXPAND_WILD); - send_to_server ("annotate\012", 0); - } - return get_responses_and_close (); - } -#endif /* CLIENT_SUPPORT */ - - if (is_rannotate) - { - DBM *db; - int i; - db = open_module (); - for (i = 0; i < argc; i++) - { - err += do_module (db, argv[i], MISC, "Annotating", rannotate_proc, - (char *) NULL, 0, local, 0, 0, (char *) NULL); - } - close_module (db); - } - else - { - err = rannotate_proc (argc + 1, argv - 1, (char *) NULL, - (char *) NULL, (char *) NULL, 0, local, (char *) NULL, - (char *) NULL); - } - - return err; -} - - -static int -rannotate_proc (argc, argv, xwhere, mwhere, mfile, shorten, local, mname, msg) - int argc; - char **argv; - char *xwhere; - char *mwhere; - char *mfile; - int shorten; - int local; - char *mname; - char *msg; -{ - /* Begin section which is identical to patch_proc--should this - be abstracted out somehow? */ - char *myargv[2]; - int err = 0; - int which; - char *repository; - char *where; - - if (is_rannotate) - { - repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0]) - + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2); - (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); - where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1) - + 1); - (void) strcpy (where, argv[0]); - - /* if mfile isn't null, we need to set up to do only part of the module */ - if (mfile != NULL) - { - char *cp; - char *path; - - /* if the portion of the module is a path, put the dir part on repos */ - if ((cp = strrchr (mfile, '/')) != NULL) - { - *cp = '\0'; - (void) strcat (repository, "/"); - (void) strcat (repository, mfile); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - mfile = cp + 1; - } - - /* take care of the rest */ - path = xmalloc (strlen (repository) + strlen (mfile) + 5); - (void) sprintf (path, "%s/%s", repository, mfile); - if (isdir (path)) - { - /* directory means repository gets the dir tacked on */ - (void) strcpy (repository, path); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - } - else - { - myargv[0] = argv[0]; - myargv[1] = mfile; - argc = 2; - argv = myargv; - } - free (path); - } - - /* cd to the starting repository */ - if ( CVS_CHDIR (repository) < 0) - { - error (0, errno, "cannot chdir to %s", repository); - free (repository); - free (where); - return (1); - } - /* End section which is identical to patch_proc. */ - - if (force_tag_match && tag != NULL) - which = W_REPOS | W_ATTIC; - else - which = W_REPOS; - } - else - { - where = NULL; - which = W_LOCAL; - repository = ""; - } - - if (tag != NULL && !tag_validated) - { - tag_check_valid (tag, argc - 1, argv + 1, local, 0, repository); - tag_validated = 1; - } - - err = start_recursion (annotate_fileproc, (FILESDONEPROC) NULL, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc - 1, argv + 1, local, which, 0, CVS_LOCK_READ, - where, 1, repository); - if ( which & W_REPOS ) - free ( repository ); - if ( where != NULL ) - free (where); - return err; -} - - -static int -annotate_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - char *expand, *version; - - if (finfo->rcs == NULL) - return (1); - - if (finfo->rcs->flags & PARTIAL) - RCS_reparsercsfile (finfo->rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - expand = RCS_getexpand (finfo->rcs); - version = RCS_getversion (finfo->rcs, tag, date, force_tag_match, - (int *) NULL); - - if (version == NULL) - return 0; - - /* Distinguish output for various files if we are processing - several files. */ - cvs_outerr ("\nAnnotations for ", 0); - cvs_outerr (finfo->fullname, 0); - cvs_outerr ("\n***************\n", 0); - - if (!force_binary && expand && expand[0] == 'b') - { - cvs_outerr ("Skipping binary file -- -F not specified.\n", 0); - } - else - { - RCS_deltas (finfo->rcs, (FILE *) NULL, (struct rcsbuffer *) NULL, - version, RCS_ANNOTATE, NULL, NULL, NULL, NULL); - } - free (version); - return 0; -} diff --git a/contrib/cvs/src/buffer.c b/contrib/cvs/src/buffer.c deleted file mode 100644 index db2bea0..0000000 --- a/contrib/cvs/src/buffer.c +++ /dev/null @@ -1,1980 +0,0 @@ -/* - * Copyright (C) 1996-2005 The Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* Code for the buffer data structure. */ - -/* $FreeBSD$ */ - -#include <assert.h> -#include "cvs.h" -#include "buffer.h" - -#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) - -#ifdef HAVE_WINSOCK_H -# include <winsock.h> -#else -# include <sys/socket.h> -#endif - -/* OS/2 doesn't have EIO. FIXME: this whole notion of turning - a different error into EIO strikes me as pretty dubious. */ -#if !defined (EIO) -#define EIO EBADPOS -#endif - -/* Linked list of available buffer_data structures. */ -static struct buffer_data *free_buffer_data; - -/* Local functions. */ -static void buf_default_memory_error PROTO ((struct buffer *)); -static void allocate_buffer_datas PROTO((void)); -static struct buffer_data *get_buffer_data PROTO((void)); - -/* Initialize a buffer structure. */ - -struct buffer * -buf_initialize (input, output, flush, block, shutdown, memory, closure) - int (*input) PROTO((void *, char *, int, int, int *)); - int (*output) PROTO((void *, const char *, int, int *)); - int (*flush) PROTO((void *)); - int (*block) PROTO((void *, int)); - int (*shutdown) PROTO((struct buffer *)); - void (*memory) PROTO((struct buffer *)); - void *closure; -{ - struct buffer *buf; - - buf = (struct buffer *) xmalloc (sizeof (struct buffer)); - buf->data = NULL; - buf->last = NULL; - buf->nonblocking = 0; - buf->input = input; - buf->output = output; - buf->flush = flush; - buf->block = block; - buf->shutdown = shutdown; - buf->memory_error = memory ? memory : buf_default_memory_error; - buf->closure = closure; - return buf; -} - -/* Free a buffer structure. */ - -void -buf_free (buf) - struct buffer *buf; -{ - if (buf->closure != NULL) - { - free (buf->closure); - buf->closure = NULL; - } - if (buf->data != NULL) - { - buf->last->next = free_buffer_data; - free_buffer_data = buf->data; - } - free (buf); -} - -/* Initialize a buffer structure which is not to be used for I/O. */ - -struct buffer * -buf_nonio_initialize (memory) - void (*memory) PROTO((struct buffer *)); -{ - return (buf_initialize - ((int (*) PROTO((void *, char *, int, int, int *))) NULL, - (int (*) PROTO((void *, const char *, int, int *))) NULL, - (int (*) PROTO((void *))) NULL, - (int (*) PROTO((void *, int))) NULL, - (int (*) PROTO((struct buffer *))) NULL, - memory, - (void *) NULL)); -} - -/* Default memory error handler. */ - -static void -buf_default_memory_error (buf) - struct buffer *buf; -{ - error (1, 0, "out of memory"); -} - -/* Allocate more buffer_data structures. */ - -static void -allocate_buffer_datas () -{ - struct buffer_data *alc; - char *space; - int i; - - /* Allocate buffer_data structures in blocks of 16. */ -#define ALLOC_COUNT (16) - - alc = xmalloc (ALLOC_COUNT * sizeof (struct buffer_data)); - space = (char *) valloc (ALLOC_COUNT * BUFFER_DATA_SIZE); - if (!space) - { - free (alc); - return; - } - for (i = 0; i < ALLOC_COUNT; i++, alc++, space += BUFFER_DATA_SIZE) - { - alc->next = free_buffer_data; - free_buffer_data = alc; - alc->text = space; - } -} - -/* Get a new buffer_data structure. */ - -static struct buffer_data * -get_buffer_data () -{ - struct buffer_data *ret; - - if (free_buffer_data == NULL) - { - allocate_buffer_datas (); - if (free_buffer_data == NULL) - return NULL; - } - - ret = free_buffer_data; - free_buffer_data = ret->next; - return ret; -} - - - -/* See whether a buffer and its file descriptor is empty. */ -int -buf_empty (buf) - struct buffer *buf; -{ - /* Try and read any data on the file descriptor first. - * We already know the descriptor is non-blocking. - */ - buf_input_data (buf, NULL); - return buf_empty_p (buf); -} - - - -/* See whether a buffer is empty. */ -int -buf_empty_p (buf) - struct buffer *buf; -{ - struct buffer_data *data; - - for (data = buf->data; data != NULL; data = data->next) - if (data->size > 0) - return 0; - return 1; -} - - - -#ifdef SERVER_FLOWCONTROL -/* - * Count how much data is stored in the buffer.. - * Note that each buffer is a xmalloc'ed chunk BUFFER_DATA_SIZE. - */ - -int -buf_count_mem (buf) - struct buffer *buf; -{ - struct buffer_data *data; - int mem = 0; - - for (data = buf->data; data != NULL; data = data->next) - mem += BUFFER_DATA_SIZE; - - return mem; -} -#endif /* SERVER_FLOWCONTROL */ - -/* Add data DATA of length LEN to BUF. */ - -void -buf_output (buf, data, len) - struct buffer *buf; - const char *data; - int len; -{ - if (buf->data != NULL - && (((buf->last->text + BUFFER_DATA_SIZE) - - (buf->last->bufp + buf->last->size)) - >= len)) - { - memcpy (buf->last->bufp + buf->last->size, data, len); - buf->last->size += len; - return; - } - - while (1) - { - struct buffer_data *newdata; - - newdata = get_buffer_data (); - if (newdata == NULL) - { - (*buf->memory_error) (buf); - return; - } - - if (buf->data == NULL) - buf->data = newdata; - else - buf->last->next = newdata; - newdata->next = NULL; - buf->last = newdata; - - newdata->bufp = newdata->text; - - if (len <= BUFFER_DATA_SIZE) - { - newdata->size = len; - memcpy (newdata->text, data, len); - return; - } - - newdata->size = BUFFER_DATA_SIZE; - memcpy (newdata->text, data, BUFFER_DATA_SIZE); - - data += BUFFER_DATA_SIZE; - len -= BUFFER_DATA_SIZE; - } - - /*NOTREACHED*/ -} - -/* Add a '\0' terminated string to BUF. */ - -void -buf_output0 (buf, string) - struct buffer *buf; - const char *string; -{ - buf_output (buf, string, strlen (string)); -} - -/* Add a single character to BUF. */ - -void -buf_append_char (buf, ch) - struct buffer *buf; - int ch; -{ - if (buf->data != NULL - && (buf->last->text + BUFFER_DATA_SIZE - != buf->last->bufp + buf->last->size)) - { - *(buf->last->bufp + buf->last->size) = ch; - ++buf->last->size; - } - else - { - char b; - - b = ch; - buf_output (buf, &b, 1); - } -} - -/* - * Send all the output we've been saving up. Returns 0 for success or - * errno code. If the buffer has been set to be nonblocking, this - * will just write until the write would block. - */ - -int -buf_send_output (buf) - struct buffer *buf; -{ - if (buf->output == NULL) - abort (); - - while (buf->data != NULL) - { - struct buffer_data *data; - - data = buf->data; - - if (data->size > 0) - { - int status, nbytes; - - status = (*buf->output) (buf->closure, data->bufp, data->size, - &nbytes); - if (status != 0) - { - /* Some sort of error. Discard the data, and return. */ - - buf->last->next = free_buffer_data; - free_buffer_data = buf->data; - buf->data = NULL; - buf->last = NULL; - - return status; - } - - if (nbytes != data->size) - { - /* Not all the data was written out. This is only - permitted in nonblocking mode. Adjust the buffer, - and return. */ - - assert (buf->nonblocking); - - data->size -= nbytes; - data->bufp += nbytes; - - return 0; - } - } - - buf->data = data->next; - data->next = free_buffer_data; - free_buffer_data = data; - } - - buf->last = NULL; - - return 0; -} - -/* - * Flush any data queued up in the buffer. If BLOCK is nonzero, then - * if the buffer is in nonblocking mode, put it into blocking mode for - * the duration of the flush. This returns 0 on success, or an error - * code. - */ - -int -buf_flush (buf, block) - struct buffer *buf; - int block; -{ - int nonblocking; - int status; - - if (buf->flush == NULL) - abort (); - - nonblocking = buf->nonblocking; - if (nonblocking && block) - { - status = set_block (buf); - if (status != 0) - return status; - } - - status = buf_send_output (buf); - if (status == 0) - status = (*buf->flush) (buf->closure); - - if (nonblocking && block) - { - int blockstat; - - blockstat = set_nonblock (buf); - if (status == 0) - status = blockstat; - } - - return status; -} - -/* - * Set buffer BUF to nonblocking I/O. Returns 0 for success or errno - * code. - */ - -int -set_nonblock (buf) - struct buffer *buf; -{ - int status; - - if (buf->nonblocking) - return 0; - if (buf->block == NULL) - abort (); - status = (*buf->block) (buf->closure, 0); - if (status != 0) - return status; - buf->nonblocking = 1; - return 0; -} - -/* - * Set buffer BUF to blocking I/O. Returns 0 for success or errno - * code. - */ - -int -set_block (buf) - struct buffer *buf; -{ - int status; - - if (! buf->nonblocking) - return 0; - if (buf->block == NULL) - abort (); - status = (*buf->block) (buf->closure, 1); - if (status != 0) - return status; - buf->nonblocking = 0; - return 0; -} - -/* - * Send a character count and some output. Returns errno code or 0 for - * success. - * - * Sending the count in binary is OK since this is only used on a pipe - * within the same system. - */ - -int -buf_send_counted (buf) - struct buffer *buf; -{ - int size; - struct buffer_data *data; - - size = 0; - for (data = buf->data; data != NULL; data = data->next) - size += data->size; - - data = get_buffer_data (); - if (data == NULL) - { - (*buf->memory_error) (buf); - return ENOMEM; - } - - data->next = buf->data; - buf->data = data; - if (buf->last == NULL) - buf->last = data; - - data->bufp = data->text; - data->size = sizeof (int); - - *((int *) data->text) = size; - - return buf_send_output (buf); -} - -/* - * Send a special count. COUNT should be negative. It will be - * handled speciallyi by buf_copy_counted. This function returns 0 or - * an errno code. - * - * Sending the count in binary is OK since this is only used on a pipe - * within the same system. - */ - -int -buf_send_special_count (buf, count) - struct buffer *buf; - int count; -{ - struct buffer_data *data; - - data = get_buffer_data (); - if (data == NULL) - { - (*buf->memory_error) (buf); - return ENOMEM; - } - - data->next = buf->data; - buf->data = data; - if (buf->last == NULL) - buf->last = data; - - data->bufp = data->text; - data->size = sizeof (int); - - *((int *) data->text) = count; - - return buf_send_output (buf); -} - -/* Append a list of buffer_data structures to an buffer. */ - -void -buf_append_data (buf, data, last) - struct buffer *buf; - struct buffer_data *data; - struct buffer_data *last; -{ - if (data != NULL) - { - if (buf->data == NULL) - buf->data = data; - else - buf->last->next = data; - buf->last = last; - } -} - -/* Append the data on one buffer to another. This removes the data - from the source buffer. */ - -void -buf_append_buffer (to, from) - struct buffer *to; - struct buffer *from; -{ - buf_append_data (to, from->data, from->last); - from->data = NULL; - from->last = NULL; -} - -/* - * Copy the contents of file F into buffer_data structures. We can't - * copy directly into an buffer, because we want to handle failure and - * succeess differently. Returns 0 on success, or -2 if out of - * memory, or a status code on error. Since the caller happens to - * know the size of the file, it is passed in as SIZE. On success, - * this function sets *RETP and *LASTP, which may be passed to - * buf_append_data. - */ - -int -buf_read_file (f, size, retp, lastp) - FILE *f; - long size; - struct buffer_data **retp; - struct buffer_data **lastp; -{ - int status; - - *retp = NULL; - *lastp = NULL; - - while (size > 0) - { - struct buffer_data *data; - int get; - - data = get_buffer_data (); - if (data == NULL) - { - status = -2; - goto error_return; - } - - if (*retp == NULL) - *retp = data; - else - (*lastp)->next = data; - data->next = NULL; - *lastp = data; - - data->bufp = data->text; - data->size = 0; - - if (size > BUFFER_DATA_SIZE) - get = BUFFER_DATA_SIZE; - else - get = size; - - errno = EIO; - if (fread (data->text, get, 1, f) != 1) - { - status = errno; - goto error_return; - } - - data->size += get; - size -= get; - } - - return 0; - - error_return: - if (*retp != NULL) - { - (*lastp)->next = free_buffer_data; - free_buffer_data = *retp; - } - return status; -} - -/* - * Copy the contents of file F into buffer_data structures. We can't - * copy directly into an buffer, because we want to handle failure and - * succeess differently. Returns 0 on success, or -2 if out of - * memory, or a status code on error. On success, this function sets - * *RETP and *LASTP, which may be passed to buf_append_data. - */ - -int -buf_read_file_to_eof (f, retp, lastp) - FILE *f; - struct buffer_data **retp; - struct buffer_data **lastp; -{ - int status; - - *retp = NULL; - *lastp = NULL; - - while (!feof (f)) - { - struct buffer_data *data; - int get, nread; - - data = get_buffer_data (); - if (data == NULL) - { - status = -2; - goto error_return; - } - - if (*retp == NULL) - *retp = data; - else - (*lastp)->next = data; - data->next = NULL; - *lastp = data; - - data->bufp = data->text; - data->size = 0; - - get = BUFFER_DATA_SIZE; - - errno = EIO; - nread = fread (data->text, 1, get, f); - if (nread == 0 && !feof (f)) - { - status = errno; - goto error_return; - } - - data->size = nread; - } - - return 0; - - error_return: - if (*retp != NULL) - { - (*lastp)->next = free_buffer_data; - free_buffer_data = *retp; - } - return status; -} - -/* Return the number of bytes in a chain of buffer_data structures. */ - -int -buf_chain_length (buf) - struct buffer_data *buf; -{ - int size = 0; - while (buf) - { - size += buf->size; - buf = buf->next; - } - return size; -} - -/* Return the number of bytes in a buffer. */ - -int -buf_length (buf) - struct buffer *buf; -{ - return buf_chain_length (buf->data); -} - -/* - * Read an arbitrary amount of data into an input buffer. The buffer - * will be in nonblocking mode, and we just grab what we can. Return - * 0 on success, or -1 on end of file, or -2 if out of memory, or an - * error code. If COUNTP is not NULL, *COUNTP is set to the number of - * bytes read. - */ - -int -buf_input_data (buf, countp) - struct buffer *buf; - int *countp; -{ - if (buf->input == NULL) - abort (); - - if (countp != NULL) - *countp = 0; - - while (1) - { - int get; - int status, nbytes; - - if (buf->data == NULL - || (buf->last->bufp + buf->last->size - == buf->last->text + BUFFER_DATA_SIZE)) - { - struct buffer_data *data; - - data = get_buffer_data (); - if (data == NULL) - { - (*buf->memory_error) (buf); - return -2; - } - - if (buf->data == NULL) - buf->data = data; - else - buf->last->next = data; - data->next = NULL; - buf->last = data; - - data->bufp = data->text; - data->size = 0; - } - - get = ((buf->last->text + BUFFER_DATA_SIZE) - - (buf->last->bufp + buf->last->size)); - - status = (*buf->input) (buf->closure, - buf->last->bufp + buf->last->size, - 0, get, &nbytes); - if (status != 0) - return status; - - buf->last->size += nbytes; - if (countp != NULL) - *countp += nbytes; - - if (nbytes < get) - { - /* If we did not fill the buffer, then presumably we read - all the available data. */ - return 0; - } - } - - /*NOTREACHED*/ -} - -/* - * Read a line (characters up to a \012) from an input buffer. (We - * use \012 rather than \n for the benefit of non Unix clients for - * which \n means something else). This returns 0 on success, or -1 - * on end of file, or -2 if out of memory, or an error code. If it - * succeeds, it sets *LINE to an allocated buffer holding the contents - * of the line. The trailing \012 is not included in the buffer. If - * LENP is not NULL, then *LENP is set to the number of bytes read; - * strlen may not work, because there may be embedded null bytes. - */ - -int -buf_read_line (buf, line, lenp) - struct buffer *buf; - char **line; - int *lenp; -{ - if (buf->input == NULL) - abort (); - - *line = NULL; - - while (1) - { - int len, finallen = 0; - struct buffer_data *data; - char *nl; - - /* See if there is a newline in BUF. */ - len = 0; - for (data = buf->data; data != NULL; data = data->next) - { - nl = memchr (data->bufp, '\012', data->size); - if (nl != NULL) - { - finallen = nl - data->bufp; - len += finallen; - break; - } - len += data->size; - } - - /* If we found a newline, copy the line into a memory buffer, - and remove it from BUF. */ - if (data != NULL) - { - char *p; - struct buffer_data *nldata; - - p = xmalloc (len + 1); - if (p == NULL) - return -2; - *line = p; - - nldata = data; - data = buf->data; - while (data != nldata) - { - struct buffer_data *next; - - memcpy (p, data->bufp, data->size); - p += data->size; - next = data->next; - data->next = free_buffer_data; - free_buffer_data = data; - data = next; - } - - memcpy (p, data->bufp, finallen); - p[finallen] = '\0'; - - data->size -= finallen + 1; - data->bufp = nl + 1; - buf->data = data; - - if (lenp != NULL) - *lenp = len; - - return 0; - } - - /* Read more data until we get a newline. */ - while (1) - { - int size, status, nbytes; - char *mem; - - if (buf->data == NULL - || (buf->last->bufp + buf->last->size - == buf->last->text + BUFFER_DATA_SIZE)) - { - data = get_buffer_data (); - if (data == NULL) - { - (*buf->memory_error) (buf); - return -2; - } - - if (buf->data == NULL) - buf->data = data; - else - buf->last->next = data; - data->next = NULL; - buf->last = data; - - data->bufp = data->text; - data->size = 0; - } - - mem = buf->last->bufp + buf->last->size; - size = (buf->last->text + BUFFER_DATA_SIZE) - mem; - - /* We need to read at least 1 byte. We can handle up to - SIZE bytes. This will only be efficient if the - underlying communication stream does its own buffering, - or is clever about getting more than 1 byte at a time. */ - status = (*buf->input) (buf->closure, mem, 1, size, &nbytes); - if (status != 0) - return status; - - buf->last->size += nbytes; - - /* Optimize slightly to avoid an unnecessary call to - memchr. */ - if (nbytes == 1) - { - if (*mem == '\012') - break; - } - else - { - if (memchr (mem, '\012', nbytes) != NULL) - break; - } - } - } -} - -/* - * Extract data from the input buffer BUF. This will read up to WANT - * bytes from the buffer. It will set *RETDATA to point at the bytes, - * and set *GOT to the number of bytes to be found there. Any buffer - * call which uses BUF may change the contents of the buffer at *DATA, - * so the data should be fully processed before any further calls are - * made. This returns 0 on success, or -1 on end of file, or -2 if - * out of memory, or an error code. - */ - -int -buf_read_data (buf, want, retdata, got) - struct buffer *buf; - int want; - char **retdata; - int *got; -{ - if (buf->input == NULL) - abort (); - - while (buf->data != NULL && buf->data->size == 0) - { - struct buffer_data *next; - - next = buf->data->next; - buf->data->next = free_buffer_data; - free_buffer_data = buf->data; - buf->data = next; - if (next == NULL) - buf->last = NULL; - } - - if (buf->data == NULL) - { - struct buffer_data *data; - int get, status, nbytes; - - data = get_buffer_data (); - if (data == NULL) - { - (*buf->memory_error) (buf); - return -2; - } - - buf->data = data; - buf->last = data; - data->next = NULL; - data->bufp = data->text; - data->size = 0; - - if (want < BUFFER_DATA_SIZE) - get = want; - else - get = BUFFER_DATA_SIZE; - status = (*buf->input) (buf->closure, data->bufp, get, - BUFFER_DATA_SIZE, &nbytes); - if (status != 0) - return status; - - data->size = nbytes; - } - - *retdata = buf->data->bufp; - if (want < buf->data->size) - { - *got = want; - buf->data->size -= want; - buf->data->bufp += want; - } - else - { - *got = buf->data->size; - buf->data->size = 0; - } - - return 0; -} - -/* - * Copy lines from an input buffer to an output buffer. This copies - * all complete lines (characters up to a newline) from INBUF to - * OUTBUF. Each line in OUTBUF is preceded by the character COMMAND - * and a space. - */ - -void -buf_copy_lines (outbuf, inbuf, command) - struct buffer *outbuf; - struct buffer *inbuf; - int command; -{ - while (1) - { - struct buffer_data *data; - struct buffer_data *nldata; - char *nl; - int len; - - /* See if there is a newline in INBUF. */ - nldata = NULL; - nl = NULL; - for (data = inbuf->data; data != NULL; data = data->next) - { - nl = memchr (data->bufp, '\n', data->size); - if (nl != NULL) - { - nldata = data; - break; - } - } - - if (nldata == NULL) - { - /* There are no more lines in INBUF. */ - return; - } - - /* Put in the command. */ - buf_append_char (outbuf, command); - buf_append_char (outbuf, ' '); - - if (inbuf->data != nldata) - { - /* - * Simply move over all the buffers up to the one containing - * the newline. - */ - for (data = inbuf->data; data->next != nldata; data = data->next) - ; - data->next = NULL; - buf_append_data (outbuf, inbuf->data, data); - inbuf->data = nldata; - } - - /* - * If the newline is at the very end of the buffer, just move - * the buffer onto OUTBUF. Otherwise we must copy the data. - */ - len = nl + 1 - nldata->bufp; - if (len == nldata->size) - { - inbuf->data = nldata->next; - if (inbuf->data == NULL) - inbuf->last = NULL; - - nldata->next = NULL; - buf_append_data (outbuf, nldata, nldata); - } - else - { - buf_output (outbuf, nldata->bufp, len); - nldata->bufp += len; - nldata->size -= len; - } - } -} - -/* - * Copy counted data from one buffer to another. The count is an - * integer, host size, host byte order (it is only used across a - * pipe). If there is enough data, it should be moved over. If there - * is not enough data, it should remain on the original buffer. A - * negative count is a special case. if one is seen, *SPECIAL is set - * to the (negative) count value and no additional data is gathered - * from the buffer; normally *SPECIAL is set to 0. This function - * returns the number of bytes it needs to see in order to actually - * copy something over. - */ - -int -buf_copy_counted (outbuf, inbuf, special) - struct buffer *outbuf; - struct buffer *inbuf; - int *special; -{ - *special = 0; - - while (1) - { - struct buffer_data *data; - int need; - union - { - char intbuf[sizeof (int)]; - int i; - } u; - char *intp; - int count; - struct buffer_data *start; - int startoff; - struct buffer_data *stop; - int stopwant; - - /* See if we have enough bytes to figure out the count. */ - need = sizeof (int); - intp = u.intbuf; - for (data = inbuf->data; data != NULL; data = data->next) - { - if (data->size >= need) - { - memcpy (intp, data->bufp, need); - break; - } - memcpy (intp, data->bufp, data->size); - intp += data->size; - need -= data->size; - } - if (data == NULL) - { - /* We don't have enough bytes to form an integer. */ - return need; - } - - count = u.i; - start = data; - startoff = need; - - if (count < 0) - { - /* A negative COUNT is a special case meaning that we - don't need any further information. */ - stop = start; - stopwant = 0; - } - else - { - /* - * We have an integer in COUNT. We have gotten all the - * data from INBUF in all buffers before START, and we - * have gotten STARTOFF bytes from START. See if we have - * enough bytes remaining in INBUF. - */ - need = count - (start->size - startoff); - if (need <= 0) - { - stop = start; - stopwant = count; - } - else - { - for (data = start->next; data != NULL; data = data->next) - { - if (need <= data->size) - break; - need -= data->size; - } - if (data == NULL) - { - /* We don't have enough bytes. */ - return need; - } - stop = data; - stopwant = need; - } - } - - /* - * We have enough bytes. Free any buffers in INBUF before - * START, and remove STARTOFF bytes from START, so that we can - * forget about STARTOFF. - */ - start->bufp += startoff; - start->size -= startoff; - - if (start->size == 0) - start = start->next; - - if (stop->size == stopwant) - { - stop = stop->next; - stopwant = 0; - } - - while (inbuf->data != start) - { - data = inbuf->data; - inbuf->data = data->next; - data->next = free_buffer_data; - free_buffer_data = data; - } - - /* If COUNT is negative, set *SPECIAL and get out now. */ - if (count < 0) - { - *special = count; - return 0; - } - - /* - * We want to copy over the bytes from START through STOP. We - * only want STOPWANT bytes from STOP. - */ - - if (start != stop) - { - /* Attach the buffers from START through STOP to OUTBUF. */ - for (data = start; data->next != stop; data = data->next) - ; - inbuf->data = stop; - data->next = NULL; - buf_append_data (outbuf, start, data); - } - - if (stopwant > 0) - { - buf_output (outbuf, stop->bufp, stopwant); - stop->bufp += stopwant; - stop->size -= stopwant; - } - } - - /*NOTREACHED*/ -} - -/* Shut down a buffer. This returns 0 on success, or an errno code. */ - -int -buf_shutdown (buf) - struct buffer *buf; -{ - if (buf->shutdown) - return (*buf->shutdown) (buf); - return 0; -} - - - -/* The simplest type of buffer is one built on top of a stdio FILE. - For simplicity, and because it is all that is required, we do not - implement setting this type of buffer into nonblocking mode. The - closure field is just a FILE *. */ - -static int stdio_buffer_input PROTO((void *, char *, int, int, int *)); -static int stdio_buffer_output PROTO((void *, const char *, int, int *)); -static int stdio_buffer_flush PROTO((void *)); -static int stdio_buffer_shutdown PROTO((struct buffer *buf)); - - - -/* Initialize a buffer built on a stdio FILE. */ -struct stdio_buffer_closure -{ - FILE *fp; - int child_pid; -}; - - - -struct buffer * -stdio_buffer_initialize (fp, child_pid, input, memory) - FILE *fp; - int child_pid; - int input; - void (*memory) PROTO((struct buffer *)); -{ - struct stdio_buffer_closure *bc = xmalloc (sizeof (*bc)); - - bc->fp = fp; - bc->child_pid = child_pid; - - return buf_initialize (input ? stdio_buffer_input : NULL, - input ? NULL : stdio_buffer_output, - input ? NULL : stdio_buffer_flush, - (int (*) PROTO((void *, int))) NULL, - stdio_buffer_shutdown, - memory, - (void *) bc); -} - -/* Return the file associated with a stdio buffer. */ -FILE * -stdio_buffer_get_file (buf) - struct buffer *buf; -{ - struct stdio_buffer_closure *bc; - - assert(buf->shutdown == stdio_buffer_shutdown); - - bc = (struct stdio_buffer_closure *) buf->closure; - - return(bc->fp); -} - -/* The buffer input function for a buffer built on a stdio FILE. */ - -static int -stdio_buffer_input (closure, data, need, size, got) - void *closure; - char *data; - int need; - int size; - int *got; -{ - struct stdio_buffer_closure *bc = (struct stdio_buffer_closure *) closure; - int nbytes; - - /* Since stdio does its own buffering, we don't worry about - getting more bytes than we need. */ - - if (need == 0 || need == 1) - { - int ch; - - ch = getc (bc->fp); - - if (ch == EOF) - { - if (feof (bc->fp)) - return -1; - else if (errno == 0) - return EIO; - else - return errno; - } - - *data = ch; - *got = 1; - return 0; - } - - nbytes = fread (data, 1, need, bc->fp); - - if (nbytes == 0) - { - *got = 0; - if (feof (bc->fp)) - return -1; - else if (errno == 0) - return EIO; - else - return errno; - } - - *got = nbytes; - - return 0; -} - -/* The buffer output function for a buffer built on a stdio FILE. */ - -static int -stdio_buffer_output (closure, data, have, wrote) - void *closure; - const char *data; - int have; - int *wrote; -{ - struct stdio_buffer_closure *bc = (struct stdio_buffer_closure *) closure; - - *wrote = 0; - - while (have > 0) - { - int nbytes; - - nbytes = fwrite (data, 1, have, bc->fp); - - if (nbytes != have) - { - if (errno == 0) - return EIO; - else - return errno; - } - - *wrote += nbytes; - have -= nbytes; - data += nbytes; - } - - return 0; -} - - - -/* The buffer flush function for a buffer built on a stdio FILE. */ -static int -stdio_buffer_flush (closure) - void *closure; -{ - struct stdio_buffer_closure *bc = (struct stdio_buffer_closure *) closure; - - if (fflush (bc->fp) != 0) - { - if (errno == 0) - return EIO; - else - return errno; - } - - return 0; -} - - - -static int -stdio_buffer_shutdown (buf) - struct buffer *buf; -{ - struct stdio_buffer_closure *bc = buf->closure; - struct stat s; - int closefp, statted; - - /* Must be a pipe or a socket. What could go wrong? - * Well, apparently for disconnected clients under AIX, the - * fstat() will return -1 on the server if the client has gone - * away. - */ - if (fstat(fileno(bc->fp), &s) == -1) statted = 0; - else statted = 1; - closefp = statted; - - /* Flush the buffer if we can */ - if (buf->flush) - { - buf_flush (buf, 1); - buf->flush = NULL; - } - - if (buf->input) - { - /* There used to be a check here for unread data in the buffer of on - * the pipe, but it was deemed unnecessary and possibly dangerous. In - * some sense it could be second-guessing the caller who requested it - * closed, as well. - */ - -# ifdef SHUTDOWN_SERVER - if (current_parsed_root->method != server_method) -# endif -# ifndef NO_SOCKET_TO_FD - { - /* shutdown() sockets */ - if (statted && S_ISSOCK (s.st_mode)) - shutdown (fileno (bc->fp), 0); - } -# endif /* NO_SOCKET_TO_FD */ -# ifdef START_RSH_WITH_POPEN_RW - /* Can't be set with SHUTDOWN_SERVER defined */ - else if (pclose (bc->fp) == EOF) - { - error (0, errno, "closing connection to %s", - current_parsed_root->hostname); - closefp = 0; - } -# endif /* START_RSH_WITH_POPEN_RW */ - - buf->input = NULL; - } - else if (buf->output) - { -# ifdef SHUTDOWN_SERVER - /* FIXME: Should have a SHUTDOWN_SERVER_INPUT & - * SHUTDOWN_SERVER_OUTPUT - */ - if (current_parsed_root->method == server_method) - SHUTDOWN_SERVER (fileno (bc->fp)); - else -# endif -# ifndef NO_SOCKET_TO_FD - /* shutdown() sockets */ - if (statted && S_ISSOCK (s.st_mode)) - shutdown (fileno (bc->fp), 1); -# else - { - /* I'm not sure I like this empty block, but the alternative - * is a another nested NO_SOCKET_TO_FD switch above. - */ - } -# endif /* NO_SOCKET_TO_FD */ - - buf->output = NULL; - } - - if (statted && closefp && fclose (bc->fp) == EOF) - { - if (server_active) - { - /* Syslog this? */ - } -# ifdef CLIENT_SUPPORT - /* We are already closing the connection. - * On error, print a warning and try to - * continue to avoid infinte loops. - */ - else - error (0, errno, - "closing down connection to %s", - current_parsed_root->hostname); -# endif /* CLIENT_SUPPORT */ - } - - /* If we were talking to a process, make sure it exited */ - if (bc->child_pid) - { - int w; - - do - w = waitpid (bc->child_pid, (int *) 0, 0); - while (w == -1 && errno == EINTR); - - /* We are already closing the connection. - * On error, print a warning and try to - * continue to avoid infinte loops. - */ - if (w == -1) - error (0, errno, "waiting for process %d", bc->child_pid); - } - return 0; -} - - - -/* Certain types of communication input and output data in packets, - where each packet is translated in some fashion. The packetizing - buffer type supports that, given a buffer which handles lower level - I/O and a routine to translate the data in a packet. - - This code uses two bytes for the size of a packet, so packets are - restricted to 65536 bytes in total. - - The translation functions should just translate; they may not - significantly increase or decrease the amount of data. The actual - size of the initial data is part of the translated data. The - output translation routine may add up to PACKET_SLOP additional - bytes, and the input translation routine should shrink the data - correspondingly. */ - -#define PACKET_SLOP (100) - -/* This structure is the closure field of a packetizing buffer. */ - -struct packetizing_buffer -{ - /* The underlying buffer. */ - struct buffer *buf; - /* The input translation function. Exactly one of inpfn and outfn - will be NULL. The input translation function should - untranslate the data in INPUT, storing the result in OUTPUT. - SIZE is the amount of data in INPUT, and is also the size of - OUTPUT. This should return 0 on success, or an errno code. */ - int (*inpfn) PROTO((void *fnclosure, const char *input, char *output, - int size)); - /* The output translation function. This should translate the - data in INPUT, storing the result in OUTPUT. The first two - bytes in INPUT will be the size of the data, and so will SIZE. - This should set *TRANSLATED to the amount of translated data in - OUTPUT. OUTPUT is large enough to hold SIZE + PACKET_SLOP - bytes. This should return 0 on success, or an errno code. */ - int (*outfn) PROTO((void *fnclosure, const char *input, char *output, - int size, int *translated)); - /* A closure for the translation function. */ - void *fnclosure; - /* For an input buffer, we may have to buffer up data here. */ - /* This is non-zero if the buffered data has been translated. - Otherwise, the buffered data has not been translated, and starts - with the two byte packet size. */ - int translated; - /* The amount of buffered data. */ - int holdsize; - /* The buffer allocated to hold the data. */ - char *holdbuf; - /* The size of holdbuf. */ - int holdbufsize; - /* If translated is set, we need another data pointer to track - where we are in holdbuf. If translated is clear, then this - pointer is not used. */ - char *holddata; -}; - -static int packetizing_buffer_input PROTO((void *, char *, int, int, int *)); -static int packetizing_buffer_output PROTO((void *, const char *, int, int *)); -static int packetizing_buffer_flush PROTO((void *)); -static int packetizing_buffer_block PROTO((void *, int)); -static int packetizing_buffer_shutdown PROTO((struct buffer *)); - -/* Create a packetizing buffer. */ - -struct buffer * -packetizing_buffer_initialize (buf, inpfn, outfn, fnclosure, memory) - struct buffer *buf; - int (*inpfn) PROTO ((void *, const char *, char *, int)); - int (*outfn) PROTO ((void *, const char *, char *, int, int *)); - void *fnclosure; - void (*memory) PROTO((struct buffer *)); -{ - struct packetizing_buffer *pb; - - pb = (struct packetizing_buffer *) xmalloc (sizeof *pb); - memset (pb, 0, sizeof *pb); - - pb->buf = buf; - pb->inpfn = inpfn; - pb->outfn = outfn; - pb->fnclosure = fnclosure; - - if (inpfn != NULL) - { - /* Add PACKET_SLOP to handle larger translated packets, and - add 2 for the count. This buffer is increased if - necessary. */ - pb->holdbufsize = BUFFER_DATA_SIZE + PACKET_SLOP + 2; - pb->holdbuf = xmalloc (pb->holdbufsize); - } - - return buf_initialize (inpfn != NULL ? packetizing_buffer_input : NULL, - inpfn != NULL ? NULL : packetizing_buffer_output, - inpfn != NULL ? NULL : packetizing_buffer_flush, - packetizing_buffer_block, - packetizing_buffer_shutdown, - memory, - pb); -} - -/* Input data from a packetizing buffer. */ - -static int -packetizing_buffer_input (closure, data, need, size, got) - void *closure; - char *data; - int need; - int size; - int *got; -{ - struct packetizing_buffer *pb = (struct packetizing_buffer *) closure; - - *got = 0; - - if (pb->holdsize > 0 && pb->translated) - { - int copy; - - copy = pb->holdsize; - - if (copy > size) - { - memcpy (data, pb->holddata, size); - pb->holdsize -= size; - pb->holddata += size; - *got = size; - return 0; - } - - memcpy (data, pb->holddata, copy); - pb->holdsize = 0; - pb->translated = 0; - - data += copy; - need -= copy; - size -= copy; - *got = copy; - } - - while (need > 0 || *got == 0) - { - int get, status, nread, count, tcount; - char *bytes; - char stackoutbuf[BUFFER_DATA_SIZE + PACKET_SLOP]; - char *inbuf, *outbuf; - - /* If we don't already have the two byte count, get it. */ - if (pb->holdsize < 2) - { - get = 2 - pb->holdsize; - status = buf_read_data (pb->buf, get, &bytes, &nread); - if (status != 0) - { - /* buf_read_data can return -2, but a buffer input - function is only supposed to return -1, 0, or an - error code. */ - if (status == -2) - status = ENOMEM; - return status; - } - - if (nread == 0) - { - /* The buffer is in nonblocking mode, and we didn't - manage to read anything. */ - return 0; - } - - if (get == 1) - pb->holdbuf[1] = bytes[0]; - else - { - pb->holdbuf[0] = bytes[0]; - if (nread < 2) - { - /* We only got one byte, but we needed two. Stash - the byte we got, and try again. */ - pb->holdsize = 1; - continue; - } - pb->holdbuf[1] = bytes[1]; - } - pb->holdsize = 2; - } - - /* Read the packet. */ - - count = (((pb->holdbuf[0] & 0xff) << 8) - + (pb->holdbuf[1] & 0xff)); - - if (count + 2 > pb->holdbufsize) - { - char *n; - - /* We didn't allocate enough space in the initialize - function. */ - - n = xrealloc (pb->holdbuf, count + 2); - if (n == NULL) - { - (*pb->buf->memory_error) (pb->buf); - return ENOMEM; - } - pb->holdbuf = n; - pb->holdbufsize = count + 2; - } - - get = count - (pb->holdsize - 2); - - status = buf_read_data (pb->buf, get, &bytes, &nread); - if (status != 0) - { - /* buf_read_data can return -2, but a buffer input - function is only supposed to return -1, 0, or an error - code. */ - if (status == -2) - status = ENOMEM; - return status; - } - - if (nread == 0) - { - /* We did not get any data. Presumably the buffer is in - nonblocking mode. */ - return 0; - } - - if (nread < get) - { - /* We did not get all the data we need to fill the packet. - buf_read_data does not promise to return all the bytes - requested, so we must try again. */ - memcpy (pb->holdbuf + pb->holdsize, bytes, nread); - pb->holdsize += nread; - continue; - } - - /* We have a complete untranslated packet of COUNT bytes. */ - - if (pb->holdsize == 2) - { - /* We just read the entire packet (the 2 bytes in - PB->HOLDBUF are the size). Save a memcpy by - translating directly from BYTES. */ - inbuf = bytes; - } - else - { - /* We already had a partial packet in PB->HOLDBUF. We - need to copy the new data over to make the input - contiguous. */ - memcpy (pb->holdbuf + pb->holdsize, bytes, nread); - inbuf = pb->holdbuf + 2; - } - - if (count <= sizeof stackoutbuf) - outbuf = stackoutbuf; - else - { - outbuf = xmalloc (count); - if (outbuf == NULL) - { - (*pb->buf->memory_error) (pb->buf); - return ENOMEM; - } - } - - status = (*pb->inpfn) (pb->fnclosure, inbuf, outbuf, count); - if (status != 0) - return status; - - /* The first two bytes in the translated buffer are the real - length of the translated data. */ - tcount = ((outbuf[0] & 0xff) << 8) + (outbuf[1] & 0xff); - - if (tcount > count) - error (1, 0, "Input translation failure"); - - if (tcount > size) - { - /* We have more data than the caller has provided space - for. We need to save some of it for the next call. */ - - memcpy (data, outbuf + 2, size); - *got += size; - - pb->holdsize = tcount - size; - memcpy (pb->holdbuf, outbuf + 2 + size, tcount - size); - pb->holddata = pb->holdbuf; - pb->translated = 1; - - if (outbuf != stackoutbuf) - free (outbuf); - - return 0; - } - - memcpy (data, outbuf + 2, tcount); - - if (outbuf != stackoutbuf) - free (outbuf); - - pb->holdsize = 0; - - data += tcount; - need -= tcount; - size -= tcount; - *got += tcount; - } - - return 0; -} - -/* Output data to a packetizing buffer. */ - -static int -packetizing_buffer_output (closure, data, have, wrote) - void *closure; - const char *data; - int have; - int *wrote; -{ - struct packetizing_buffer *pb = (struct packetizing_buffer *) closure; - char inbuf[BUFFER_DATA_SIZE + 2]; - char stack_outbuf[BUFFER_DATA_SIZE + PACKET_SLOP + 4]; - struct buffer_data *outdata = NULL; - char *outbuf; - int size, status, translated; - - if (have > BUFFER_DATA_SIZE) - { - /* It would be easy to xmalloc a buffer, but I don't think this - case can ever arise. */ - abort (); - } - - inbuf[0] = (have >> 8) & 0xff; - inbuf[1] = have & 0xff; - memcpy (inbuf + 2, data, have); - - size = have + 2; - - /* The output function is permitted to add up to PACKET_SLOP - bytes, and we need 2 bytes for the size of the translated data. - If we can guarantee that the result will fit in a buffer_data, - we translate directly into one to avoid a memcpy in buf_output. */ - if (size + PACKET_SLOP + 2 > BUFFER_DATA_SIZE) - outbuf = stack_outbuf; - else - { - outdata = get_buffer_data (); - if (outdata == NULL) - { - (*pb->buf->memory_error) (pb->buf); - return ENOMEM; - } - - outdata->next = NULL; - outdata->bufp = outdata->text; - - outbuf = outdata->text; - } - - status = (*pb->outfn) (pb->fnclosure, inbuf, outbuf + 2, size, - &translated); - if (status != 0) - return status; - - /* The output function is permitted to add up to PACKET_SLOP - bytes. */ - if (translated > size + PACKET_SLOP) - abort (); - - outbuf[0] = (translated >> 8) & 0xff; - outbuf[1] = translated & 0xff; - - if (outbuf == stack_outbuf) - buf_output (pb->buf, outbuf, translated + 2); - else - { - /* if ((have + PACKET_SLOP + 4) > BUFFER_DATA_SIZE), then - outdata may be NULL. */ - if (outdata == NULL) - abort (); - - outdata->size = translated + 2; - buf_append_data (pb->buf, outdata, outdata); - } - - *wrote = have; - - /* We will only be here because buf_send_output was called on the - packetizing buffer. That means that we should now call - buf_send_output on the underlying buffer. */ - return buf_send_output (pb->buf); -} - - - -/* Flush data to a packetizing buffer. */ -static int -packetizing_buffer_flush (closure) - void *closure; -{ - struct packetizing_buffer *pb = (struct packetizing_buffer *) closure; - - /* Flush the underlying buffer. Note that if the original call to - buf_flush passed 1 for the BLOCK argument, then the buffer will - already have been set into blocking mode, so we should always - pass 0 here. */ - return buf_flush (pb->buf, 0); -} - - - -/* The block routine for a packetizing buffer. */ -static int -packetizing_buffer_block (closure, block) - void *closure; - int block; -{ - struct packetizing_buffer *pb = (struct packetizing_buffer *) closure; - - if (block) - return set_block (pb->buf); - else - return set_nonblock (pb->buf); -} - -/* Shut down a packetizing buffer. */ - -static int -packetizing_buffer_shutdown (buf) - struct buffer *buf; -{ - struct packetizing_buffer *pb = (struct packetizing_buffer *) buf->closure; - - return buf_shutdown (pb->buf); -} - -#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */ diff --git a/contrib/cvs/src/buffer.h b/contrib/cvs/src/buffer.h deleted file mode 100644 index 3459058..0000000 --- a/contrib/cvs/src/buffer.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 1996-2005 The Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* Declarations concerning the buffer data structure. */ - -#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) - -/* - * We must read data from a child process and send it across the - * network. We do not want to block on writing to the network, so we - * store the data from the child process in memory. A BUFFER - * structure holds the status of one communication, and uses a linked - * list of buffer_data structures to hold data. - */ - -struct buffer -{ - /* Data. */ - struct buffer_data *data; - - /* Last buffer on data chain. */ - struct buffer_data *last; - - /* Nonzero if the buffer is in nonblocking mode. */ - int nonblocking; - - /* Functions must be provided to transfer data in and out of the - buffer. Either the input or output field must be set, but not - both. */ - - /* Read data into the buffer DATA. There is room for up to SIZE - bytes. In blocking mode, wait until some input, at least NEED - bytes, is available (NEED may be 0 but that is the same as NEED - == 1). In non-blocking mode return immediately no matter how - much input is available; NEED is ignored. Return 0 on success, - or -1 on end of file, or an errno code. Set the number of - bytes read in *GOT. - - If there are a nonzero number of bytes available, less than NEED, - followed by end of file, just read those bytes and return 0. */ - int (*input) PROTO((void *closure, char *data, int need, int size, - int *got)); - - /* Write data. This should write up to HAVE bytes from DATA. - This should return 0 on success, or an errno code. It should - set the number of bytes written in *WROTE. */ - int (*output) PROTO((void *closure, const char *data, int have, - int *wrote)); - - /* Flush any data which may be buffered up after previous calls to - OUTPUT. This should return 0 on success, or an errno code. */ - int (*flush) PROTO((void *closure)); - - /* Change the blocking mode of the underlying communication - stream. If BLOCK is non-zero, it should be placed into - blocking mode. Otherwise, it should be placed into - non-blocking mode. This should return 0 on success, or an - errno code. */ - int (*block) PROTO ((void *closure, int block)); - - /* Shut down the communication stream. This does not mean that it - should be closed. It merely means that no more data will be - read or written, and that any final processing that is - appropriate should be done at this point. This may be NULL. - It should return 0 on success, or an errno code. This entry - point exists for the compression code. */ - int (*shutdown) PROTO((struct buffer *)); - - /* This field is passed to the INPUT, OUTPUT, and BLOCK functions. */ - void *closure; - - /* Function to call if we can't allocate memory. */ - void (*memory_error) PROTO((struct buffer *)); -}; - -/* Data is stored in lists of these structures. */ - -struct buffer_data -{ - /* Next buffer in linked list. */ - struct buffer_data *next; - - /* - * A pointer into the data area pointed to by the text field. This - * is where to find data that has not yet been written out. - */ - char *bufp; - - /* The number of data bytes found at BUFP. */ - int size; - - /* - * Actual buffer. This never changes after the structure is - * allocated. The buffer is BUFFER_DATA_SIZE bytes. - */ - char *text; -}; - -/* The size we allocate for each buffer_data structure. */ -#define BUFFER_DATA_SIZE (4096) - -/* The type of a function passed as a memory error handler. */ -typedef void (*BUFMEMERRPROC) PROTO ((struct buffer *)); - -extern struct buffer *buf_initialize PROTO((int (*) (void *, char *, int, - int, int *), - int (*) (void *, const char *, - int, int *), - int (*) (void *), - int (*) (void *, int), - int (*) (struct buffer *), - void (*) (struct buffer *), - void *)); -extern void buf_free PROTO((struct buffer *)); -extern struct buffer *buf_nonio_initialize PROTO((void (*) (struct buffer *))); -extern struct buffer *stdio_buffer_initialize - PROTO((FILE *, int, int, void (*) (struct buffer *))); -extern FILE *stdio_buffer_get_file PROTO((struct buffer *)); -extern struct buffer *compress_buffer_initialize - PROTO((struct buffer *, int, int, void (*) (struct buffer *))); -extern struct buffer *packetizing_buffer_initialize - PROTO((struct buffer *, int (*) (void *, const char *, char *, int), - int (*) (void *, const char *, char *, int, int *), void *, - void (*) (struct buffer *))); -extern int buf_empty PROTO((struct buffer *)); -extern int buf_empty_p PROTO((struct buffer *)); -extern void buf_output PROTO((struct buffer *, const char *, int)); -extern void buf_output0 PROTO((struct buffer *, const char *)); -extern void buf_append_char PROTO((struct buffer *, int)); -extern int buf_send_output PROTO((struct buffer *)); -extern int buf_flush PROTO((struct buffer *, int)); -extern int set_nonblock PROTO((struct buffer *)); -extern int set_block PROTO((struct buffer *)); -extern int buf_send_counted PROTO((struct buffer *)); -extern int buf_send_special_count PROTO((struct buffer *, int)); -extern void buf_append_data PROTO((struct buffer *, - struct buffer_data *, - struct buffer_data *)); -extern void buf_append_buffer PROTO((struct buffer *, struct buffer *)); -extern int buf_read_file PROTO((FILE *, long, struct buffer_data **, - struct buffer_data **)); -extern int buf_read_file_to_eof PROTO((FILE *, struct buffer_data **, - struct buffer_data **)); -extern int buf_input_data PROTO((struct buffer *, int *)); -extern int buf_read_line PROTO((struct buffer *, char **, int *)); -extern int buf_read_data PROTO((struct buffer *, int, char **, int *)); -extern void buf_copy_lines PROTO((struct buffer *, struct buffer *, int)); -extern int buf_copy_counted PROTO((struct buffer *, struct buffer *, int *)); -extern int buf_chain_length PROTO((struct buffer_data *)); -extern int buf_length PROTO((struct buffer *)); -extern int buf_shutdown PROTO((struct buffer *)); - -#ifdef SERVER_FLOWCONTROL -extern int buf_count_mem PROTO((struct buffer *)); -#endif /* SERVER_FLOWCONTROL */ - -#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */ diff --git a/contrib/cvs/src/checkin.c b/contrib/cvs/src/checkin.c deleted file mode 100644 index 06d431f..0000000 --- a/contrib/cvs/src/checkin.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Check In - * - * Does a very careful checkin of the file "user", and tries not to spoil its - * modification time (to avoid needless recompilations). When RCS ID keywords - * get expanded on checkout, however, the modification time is updated and - * there is no good way to get around this. - * - * Returns non-zero on error. - */ - -#include <assert.h> -#include "cvs.h" -#include "fileattr.h" -#include "edit.h" - -int -Checkin (type, finfo, rev, tag, options, message) - int type; - struct file_info *finfo; - char *rev; - char *tag; - char *options; - char *message; -{ - Vers_TS *vers; - int set_time; - char *tocvsPath = NULL; - - /* Hmm. This message goes to stdout and the "foo,v <-- foo" - message from "ci" goes to stderr. This doesn't make a whole - lot of sense, but making everything go to stdout can only be - gracefully achieved once RCS_checkin is librarified. */ - cvs_output ("Checking in ", 0); - cvs_output (finfo->fullname, 0); - cvs_output (";\n", 0); - - tocvsPath = wrap_tocvs_process_file (finfo->file); - if (!noexec) - { - if (tocvsPath) - { - if (unlink_file_dir (finfo->file) < 0) - if (! existence_error (errno)) - error (1, errno, "cannot remove %s", finfo->fullname); - rename_file (tocvsPath, finfo->file); - } - } - - /* There use to be a check for finfo->rcs == NULL here and then a - * call to RCS_parse when necessary, but Checkin() isn't called - * if the RCS file hasn't already been parsed in one of the - * check functions. - */ - assert (finfo->rcs != NULL); - - switch (RCS_checkin (finfo->rcs, finfo->file, message, rev, 0, - RCS_FLAGS_KEEPFILE)) - { - case 0: /* everything normal */ - - /* The checkin succeeded. If checking the file out again - would not cause any changes, we are done. Otherwise, - we need to check out the file, which will change the - modification time of the file. - - The only way checking out the file could cause any - changes is if the file contains RCS keywords. So we if - we are not expanding RCS keywords, we are done. */ - - if (options != NULL - && strcmp (options, "-V4") == 0) /* upgrade to V5 now */ - options[0] = '\0'; - - /* FIXME: If PreservePermissions is on, RCS_cmp_file is - going to call RCS_checkout into a temporary file - anyhow. In that case, it would be more efficient to - call RCS_checkout here, compare the resulting files - using xcmp, and rename if necessary. I think this - should be fixed in RCS_cmp_file. */ - if( ( ! preserve_perms - && options != NULL - && ( strcmp( options, "-ko" ) == 0 - || strcmp( options, "-kb" ) == 0 ) ) - || RCS_cmp_file( finfo->rcs, rev, (char **)NULL, (char *)NULL, - options, finfo->file ) == 0 ) - { - /* The existing file is correct. We don't have to do - anything. */ - set_time = 0; - } - else - { - /* The existing file is incorrect. We need to check - out the correct file contents. */ - if (RCS_checkout (finfo->rcs, finfo->file, rev, (char *) NULL, - options, RUN_TTY, (RCSCHECKOUTPROC) NULL, - (void *) NULL) != 0) - error (1, 0, "failed when checking out new copy of %s", - finfo->fullname); - xchmod (finfo->file, 1); - set_time = 1; - } - - wrap_fromcvs_process_file (finfo->file); - - /* - * If we want read-only files, muck the permissions here, before - * getting the file time-stamp. - */ - if (!cvswrite || fileattr_get (finfo->file, "_watched")) - xchmod (finfo->file, 0); - - /* Re-register with the new data. */ - vers = Version_TS (finfo, NULL, tag, NULL, 1, set_time); - if (strcmp (vers->options, "-V4") == 0) - vers->options[0] = '\0'; - Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_user, - vers->options, vers->tag, vers->date, (char *) 0); - history_write (type, NULL, vers->vn_rcs, - finfo->file, finfo->repository); - - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - - break; - - case -1: /* fork failed */ - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - - if (!noexec) - error (1, errno, "could not check in %s -- fork failed", - finfo->fullname); - return (1); - - default: /* ci failed */ - - /* The checkin failed, for some unknown reason, so we - print an error, and return an error. We assume that - the original file has not been touched. */ - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - - if (!noexec) - error (0, 0, "could not check in %s", finfo->fullname); - return (1); - } - - /* - * When checking in a specific revision, we may have locked the wrong - * branch, so to be sure, we do an extra unlock here before - * returning. - */ - if (rev) - { - (void) RCS_unlock (finfo->rcs, NULL, 1); - RCS_rewrite (finfo->rcs, NULL, NULL); - } - -#ifdef SERVER_SUPPORT - if (server_active) - { - if (set_time) - /* Need to update the checked out file on the client side. */ - server_updated (finfo, vers, SERVER_UPDATED, - (mode_t) -1, (unsigned char *) NULL, - (struct buffer *) NULL); - else - server_checked_in (finfo->file, finfo->update_dir, finfo->repository); - } - else -#endif - mark_up_to_date (finfo->file); - - freevers_ts (&vers); - return 0; -} diff --git a/contrib/cvs/src/checkout.c b/contrib/cvs/src/checkout.c deleted file mode 100644 index a1cd6cc..0000000 --- a/contrib/cvs/src/checkout.c +++ /dev/null @@ -1,1284 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Create Version - * - * "checkout" creates a "version" of an RCS repository. This version is owned - * totally by the user and is actually an independent copy, to be dealt with - * as seen fit. Once "checkout" has been called in a given directory, it - * never needs to be called again. The user can keep up-to-date by calling - * "update" when he feels like it; this will supply him with a merge of his - * own modifications and the changes made in the RCS original. See "update" - * for details. - * - * "checkout" can be given a list of directories or files to be updated and in - * the case of a directory, will recursivley create any sub-directories that - * exist in the repository. - * - * When the user is satisfied with his own modifications, the present version - * can be committed by "commit"; this keeps the present version in tact, - * usually. - * - * The call is cvs checkout [options] <module-name>... - * - * "checkout" creates a directory ./CVS, in which it keeps its administration, - * in two files, Repository and Entries. The first contains the name of the - * repository. The second contains one line for each registered file, - * consisting of the version number it derives from, its time stamp at - * derivation time and its name. Both files are normal files and can be - * edited by the user, if necessary (when the repository is moved, e.g.) - */ - -/* - * $FreeBSD$ - */ - -#include <assert.h> -#include "cvs.h" - -static char *findslash PROTO((char *start, char *p)); -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 const char *const checkout_usage[] = -{ - "Usage:\n %s %s [-ANPRcflnps] [-r rev] [-D date] [-d dir]\n", - " [-j rev1] [-j rev2] [-k kopt] modules...\n", - "\t-A\tReset any sticky tags/date/kopts.\n", - "\t-N\tDon't shorten module paths if -d specified.\n", - "\t-P\tPrune empty directories.\n", - "\t-R\tProcess directories recursively.\n", - "\t-T\tCreate Template file from local repository for remote commit.\n", - "\t-c\t\"cat\" the module database.\n", - "\t-f\tForce a head revision match if tag/date not found.\n", - "\t-l\tLocal directory only, not recursive\n", - "\t-n\tDo not run module program (if any).\n", - "\t-p\tCheck out files to standard output (avoids stickiness).\n", - "\t-s\tLike -c, but include module status.\n", - "\t-r rev\tCheck out revision or tag. (implies -P) (is sticky)\n", - "\t-D date\tCheck out revisions as of date. (implies -P) (is sticky)\n", - "\t-d dir\tCheck out into dir instead of module name.\n", - "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n", - "\t-j rev\tMerge in changes made between current revision and rev.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -static const char *const export_usage[] = -{ - "Usage: %s %s [-NRfln] [-r tag] [-D date] [-d dir] [-k kopt] module...\n", - "\t-N\tDon't shorten module paths if -d specified.\n", - "\t-f\tForce a head revision match if tag/date not found.\n", - "\t-l\tLocal directory only, not recursive\n", - "\t-R\tProcess directories recursively (default).\n", - "\t-n\tDo not run module program (if any).\n", - "\t-r tag\tExport tagged revisions.\n", - "\t-D date\tExport revisions as of date.\n", - "\t-d dir\tExport into dir instead of module name.\n", - "\t-k kopt\tUse RCS kopt -k option on checkout.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -static int checkout_prune_dirs; -static int force_tag_match; -static int pipeout; -static int aflag; -static char *options; -static char *tag; -static int tag_validated; -static char *date; -static char *join_rev1; -static char *join_rev2; -static int join_tags_validated; -static int pull_template; -static char *preload_update_dir; -static char *history_name; -static enum mtype m_type; - -int -checkout (argc, argv) - int argc; - char **argv; -{ - int i; - int c; - DBM *db; - int cat = 0, err = 0, status = 0; - int run_module_prog = 1; - int local = 0; - int shorten = -1; - char *where = NULL; - char *valid_options; - const char *const *valid_usage; - - /* initialize static options */ - force_tag_match = 1; - if (options) - { - free (options); - options = NULL; - } - tag = date = join_rev1 = join_rev2 = preload_update_dir = NULL; - history_name = NULL; - tag_validated = join_tags_validated = 0; - - - /* - * A smaller subset of options are allowed for the export command, which - * is essentially like checkout, except that it hard-codes certain - * options to be default (like -kv) and takes care to remove the CVS - * directory when it has done its duty - */ - if (strcmp (cvs_cmd_name, "export") == 0) - { - m_type = EXPORT; - valid_options = "+Nnk:d:flRQqr:D:"; - valid_usage = export_usage; - } - else - { - m_type = CHECKOUT; - valid_options = "+ANnk:d:flRpTQqcsr:D:j:P"; - valid_usage = checkout_usage; - } - - if (argc == -1) - usage (valid_usage); - - ign_setup (); - wrap_setup (); - - optind = 0; - while ((c = getopt (argc, argv, valid_options)) != -1) - { - switch (c) - { - case 'A': - aflag = 1; - break; - case 'N': - shorten = 0; - break; - case 'k': - if (options) - free (options); - options = RCS_check_kflag (optarg); - break; - case 'n': - run_module_prog = 0; - break; - case 'T': - pull_template = 1; - break; - case 'Q': - case 'q': - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) - error (1, 0, - "-q or -Q must be specified before \"%s\"", - cvs_cmd_name); - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'P': - checkout_prune_dirs = 1; - break; - case 'p': - pipeout = 1; - run_module_prog = 0; /* don't run module prog when piping */ - noexec = 1; /* so no locks will be created */ - break; - case 'c': - cat = 1; - break; - case 'd': - where = optarg; - if (shorten == -1) - shorten = 1; - break; - case 's': - cat = status = 1; - break; - case 'f': - force_tag_match = 0; - break; - case 'r': - tag = optarg; - checkout_prune_dirs = 1; - break; - case 'D': - date = Make_Date (optarg); - checkout_prune_dirs = 1; - break; - case 'j': - if (join_rev2) - error (1, 0, "only two -j options can be specified"); - if (join_rev1) - join_rev2 = optarg; - else - join_rev1 = optarg; - break; - case '?': - default: - usage (valid_usage); - break; - } - } - argc -= optind; - argv += optind; - - if (shorten == -1) - shorten = 0; - - if (cat && argc != 0) - error (1, 0, "-c and -s must not get any arguments"); - - if (!cat && argc == 0) - error (1, 0, "must specify at least one module or directory"); - - if (where && pipeout) - error (1, 0, "-d and -p are mutually exclusive"); - - if (m_type == EXPORT) - { - if (!tag && !date) - error (1, 0, "must specify a tag or date"); - - if (tag && isdigit ((unsigned char) tag[0])) - error (1, 0, "tag `%s' must be a symbolic tag", tag); - } - -#ifdef SERVER_SUPPORT - if (server_active && where != NULL) - { - server_pathname_check (where); - } -#endif - - if (!cat && !pipeout && !safe_location( where )) { - error(1, 0, "Cannot check out files into the repository itself"); - } - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - int expand_modules; - - start_server (); - - ign_setup (); - - expand_modules = (!cat && !pipeout - && supported_request ("expand-modules")); - - if (expand_modules) - { - /* This is done here because we need to read responses - from the server before we send the command checkout or - export files. */ - - client_expand_modules (argc, argv, local); - } - - if (!run_module_prog) - send_arg ("-n"); - if (local) - send_arg ("-l"); - if (pipeout) - send_arg ("-p"); - if (!force_tag_match) - send_arg ("-f"); - if (aflag) - send_arg("-A"); - if (!shorten) - send_arg("-N"); - if (checkout_prune_dirs && m_type == CHECKOUT) - send_arg("-P"); - client_prune_dirs = checkout_prune_dirs; - if (cat && !status) - send_arg("-c"); - if (where != NULL) - option_with_arg ("-d", where); - if (status) - send_arg("-s"); - if (options != NULL && options[0] != '\0') - send_arg (options); - option_with_arg ("-r", tag); - if (date) - client_senddate (date); - if (join_rev1 != NULL) - option_with_arg ("-j", join_rev1); - if (join_rev2 != NULL) - option_with_arg ("-j", join_rev2); - send_arg ("--"); - - if (expand_modules) - { - client_send_expansions (local, where, 1); - } - else - { - int i; - for (i = 0; i < argc; ++i) - send_arg (argv[i]); - client_nonexpanded_setup (); - } - - send_to_server (m_type == EXPORT ? "export\012" : "co\012", 0); - return get_responses_and_close (); - } -#endif /* CLIENT_SUPPORT */ - - if (cat) - { - cat_module (status); - if (options) - { - free (options); - options = NULL; - } - return (0); - } - db = open_module (); - - - /* If we've specified something like "cvs co foo/bar baz/quux" - don't try to shorten names. There are a few cases in which we - could shorten (e.g. "cvs co foo/bar foo/baz"), but we don't - handle those yet. Better to have an extra directory created - than the thing checked out under the wrong directory name. */ - - if (argc > 1) - shorten = 0; - - - /* If we will be calling history_write, work out the name to pass - it. */ - if (!pipeout) - { - if (!date) - history_name = tag; - else if (!tag) - history_name = date; - else - { - history_name = xmalloc (strlen (tag) + strlen (date) + 2); - sprintf (history_name, "%s:%s", tag, date); - } - } - - - for (i = 0; i < argc; i++) - err += do_module (db, argv[i], m_type, "Updating", checkout_proc, - where, shorten, local, run_module_prog, !pipeout, - (char *) NULL); - close_module (db); - if (options) - { - free (options); - options = NULL; - } - if (history_name != tag && history_name != date && history_name != NULL) - free (history_name); - return (err); -} - -/* FIXME: This is and emptydir_name are in checkout.c for historical - reasons, probably want to move them. */ - -/* int - * safe_location ( char *where ) - * - * Return true if where is a safe destination for a checkout. - * - * INPUTS - * where The requested destination directory. - * - * GLOBALS - * current_parsed_root->directory - * current_parsed_root->isremote - * Used to locate our CVSROOT. - * - * RETURNS - * true If we are running in client mode or if where is not located - * within the CVSROOT. - * false Otherwise. - * - * ERRORS - * Exits with a fatal error message when various events occur, such as not - * being able to resolve a path or failing ot chdir to a path. - */ -int -safe_location (where) - char *where; -{ - char *current; - char *where_location; - char *hardpath; - size_t hardpath_len; - int retval; - - if (trace) - (void) fprintf (stderr, "%s-> safe_location( where=%s )\n", - CLIENT_SERVER_STR, - where ? where : "(null)"); - - /* Don't compare remote CVSROOTs to our destination directory. */ - if (current_parsed_root->isremote) return 1; - - /* set current - even if where is set we'll need to cd back... */ - current = xgetwd (); - if (current == NULL) - error (1, errno, "could not get working directory"); - - hardpath = xresolvepath ( current_parsed_root->directory ); - - /* if where is set, set current to where, where - last_component( where ), - * or fail, depending on whether the directories exist or not. - */ - if( where != NULL ) - { - if( chdir( where ) != -1 ) - { - /* where */ - where_location = xgetwd(); - if( where_location == NULL ) - error( 1, errno, "could not get working directory" ); - - if( chdir( current ) == -1 ) - error( 1, errno, "could not change directory to `%s'", current ); - - free( current ); - current = where_location; - } - else if( errno == ENOENT ) - { - if ( last_component( where ) != where ) - { - /* where - last_component( where ) */ - char *parent; - - /* strip the last_component */ - where_location = xstrdup (where); - /* It's okay to cast out the const below since we know we just - * allocated where_location and can do what we like with it. - */ - parent = (char *)last_component (where_location); - parent[-1] = '\0'; - - if( chdir( where_location ) != -1 ) - { - free( where_location ); - where_location = xgetwd(); - if( where_location == NULL ) - error( 1, errno, "could not get working directory (nominally `%s')", where_location ); - - if( chdir( current ) == -1 ) - error( 1, errno, "could not change directory to `%s'", current ); - - free( current ); - current = where_location; - } - else - /* fail */ - error( 1, errno, "could not change directory to requested checkout directory `%s'", where_location ); - } - /* else: ERRNO == ENOENT & last_component(where) == where - * for example, 'cvs co -d newdir module', where newdir hasn't - * been created yet, so leave current set to '.' and check that - */ - } - else - /* fail */ - error( 1, errno, "could not change directory to requested checkout directory `%s'", where ); - } - - hardpath_len = strlen (hardpath); - if (strlen (current) >= hardpath_len - && strncmp (current, hardpath, hardpath_len) == 0) - { - if (/* Current is a subdirectory of hardpath. */ - current[hardpath_len] == '/' - - /* Current is hardpath itself. */ - || current[hardpath_len] == '\0') - retval = 0; - else - /* It isn't a problem. For example, current is - "/foo/cvsroot-bar" and hardpath is "/foo/cvsroot". */ - retval = 1; - } - else - retval = 1; - free (current); - free (hardpath); - return retval; -} - -struct dir_to_build -{ - /* What to put in CVS/Repository. */ - char *repository; - /* The path to the directory. */ - char *dirpath; - - /* If set, don't build the directory, just change to it. - The caller will also want to set REPOSITORY to NULL. */ - int just_chdir; - - struct dir_to_build *next; -}; - -static int build_dirs_and_chdir PROTO ((struct dir_to_build *list, - int sticky)); - -static void build_one_dir PROTO ((char *, char *, int)); - -static void -build_one_dir (repository, dirpath, sticky) - char *repository; - char *dirpath; - int sticky; -{ - FILE *fp; - - 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)) - error (1, 0, "there is no repository %s", repository); - - if (Create_Admin (".", dirpath, repository, - sticky ? tag : (char *) NULL, - sticky ? date : (char *) NULL, - - /* FIXME? This is a guess. If it is important - for nonbranch to be set correctly here I - think we need to write it one way now and - then rewrite it later via WriteTag, once - we've had a chance to call RCS_nodeisbranch - on each file. */ - 0, 1, 1)) - return; - - if (!noexec) - { - 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 (dirpath, repository); -#endif - } - } -} - -/* - * process_module calls us back here so we do the actual checkout stuff - */ -/* ARGSUSED */ -static int -checkout_proc (argc, argv, where_orig, mwhere, mfile, shorten, - local_specified, omodule, msg) - int argc; - char **argv; - char *where_orig; - char *mwhere; - char *mfile; - int shorten; - int local_specified; - char *omodule; - char *msg; -{ - char *myargv[2]; - int err = 0; - int which; - char *cp; - char *repository; - char *oldupdate = NULL; - char *where; - - /* - * OK, so we're doing the checkout! Our args are as follows: - * argc,argv contain either dir or dir followed by a list of files - * where contains where to put it (if supplied by checkout) - * mwhere contains the module name or -d from module file - * mfile says do only that part of the module - * shorten = 1 says shorten as much as possible - * omodule is the original arg to do_module() - */ - - /* Set up the repository (maybe) for the bottom directory. - Allocate more space than we need so we don't need to keep - reallocating this string. */ - repository = xmalloc (strlen (current_parsed_root->directory) - + strlen (argv[0]) - + (mfile == NULL ? 0 : strlen (mfile)) - + 10); - (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); - Sanitize_Repository_Name (repository); - - - /* save the original value of preload_update_dir */ - if (preload_update_dir != NULL) - oldupdate = xstrdup (preload_update_dir); - - - /* Allocate space and set up the where variable. We allocate more - space than necessary here so that we don't have to keep - reallocaing it later on. */ - - where = xmalloc (strlen (argv[0]) - + (mfile == NULL ? 0 : strlen (mfile)) - + (mwhere == NULL ? 0 : strlen (mwhere)) - + (where_orig == NULL ? 0 : strlen (where_orig)) - + 10); - - /* Yes, this could be written in a less verbose way, but in this - form it is quite easy to read. - - FIXME? The following code that sets should probably be moved - to do_module in modules.c, since there is similar code in - patch.c and rtag.c. */ - - if (shorten) - { - if (where_orig != NULL) - { - /* If the user has specified a directory with `-d' on the - command line, use it preferentially, even over the `-d' - flag in the modules file. */ - - (void) strcpy (where, where_orig); - } - else if (mwhere != NULL) - { - /* Second preference is the value of mwhere, which is from - the `-d' flag in the modules file. */ - - (void) strcpy (where, mwhere); - } - else - { - /* Third preference is the directory specified in argv[0] - which is this module'e directory in the repository. */ - - (void) strcpy (where, argv[0]); - } - } - else - { - /* Use the same preferences here, bug don't shorten -- that - is, tack on where_orig if it exists. */ - - *where = '\0'; - - if (where_orig != NULL) - { - (void) strcat (where, where_orig); - (void) strcat (where, "/"); - } - - /* If the -d flag in the modules file specified an absolute - directory, let the user override it with the command-line - -d option. */ - - if ((mwhere != NULL) && (! isabsolute (mwhere))) - (void) strcat (where, mwhere); - else - (void) strcat (where, argv[0]); - } - strip_trailing_slashes (where); /* necessary? */ - - - /* At this point, the user may have asked for a single file or - directory from within a module. In that case, we should modify - where, repository, and argv as appropriate. */ - - if (mfile != NULL) - { - /* The mfile variable can have one or more path elements. If - it has multiple elements, we want to tack those onto both - repository and where. The last element may refer to either - a file or directory. Here's what to do: - - it refers to a directory - -> simply tack it on to where and repository - it refers to a file - -> munge argv to contain `basename mfile` */ - - char *cp; - char *path; - - - /* Paranoia check. */ - - if (mfile[strlen (mfile) - 1] == '/') - { - error (0, 0, "checkout_proc: trailing slash on mfile (%s)!", - mfile); - } - - - /* Does mfile have multiple path elements? */ - - cp = strrchr (mfile, '/'); - if (cp != NULL) - { - *cp = '\0'; - (void) strcat (repository, "/"); - (void) strcat (repository, mfile); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - mfile = cp + 1; - } - - - /* Now mfile is a single path element. */ - - path = xmalloc (strlen (repository) + strlen (mfile) + 5); - (void) sprintf (path, "%s/%s", repository, mfile); - if (isdir (path)) - { - /* It's a directory, so tack it on to repository and - where, as we did above. */ - - (void) strcat (repository, "/"); - (void) strcat (repository, mfile); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - } - else - { - /* It's a file, which means we have to screw around with - argv. */ - myargv[0] = argv[0]; - myargv[1] = mfile; - argc = 2; - argv = myargv; - } - free (path); - } - - if (preload_update_dir != NULL) - { - preload_update_dir = - xrealloc (preload_update_dir, - strlen (preload_update_dir) + strlen (where) + 5); - strcat (preload_update_dir, "/"); - strcat (preload_update_dir, where); - } - else - preload_update_dir = xstrdup (where); - - /* - * At this point, where is the directory we want to build, repository is - * the repository for the lowest level of the path. - * - * We need to tell build_dirs not only the path we want it to - * build, but also the repositories we want it to populate the - * path with. To accomplish this, we walk the path backwards, one - * pathname component at a time, constucting a linked list of - * struct dir_to_build. - */ - - /* - * If we are sending everything to stdout, we can skip a whole bunch of - * work from here - */ - if (!pipeout) - { - struct dir_to_build *head; - char *reposcopy; - - if (strncmp (repository, current_parsed_root->directory, - strlen (current_parsed_root->directory)) != 0) - error (1, 0, "\ -internal error: %s doesn't start with %s in checkout_proc", - repository, current_parsed_root->directory); - - /* We always create at least one directory, which corresponds to - the entire strings for WHERE and REPOSITORY. */ - head = (struct dir_to_build *) xmalloc (sizeof (struct dir_to_build)); - /* Special marker to indicate that we don't want build_dirs_and_chdir - to create the CVSADM directory for us. */ - head->repository = NULL; - head->dirpath = xstrdup (where); - head->next = NULL; - head->just_chdir = 0; - - - /* Make a copy of the repository name to play with. */ - reposcopy = xstrdup (repository); - - /* FIXME: this should be written in terms of last_component - instead of hardcoding '/'. This presumably affects OS/2, - NT, &c, if the user specifies '\'. Likewise for the call - to findslash. */ - cp = where + strlen (where); - while (cp > where) - { - struct dir_to_build *new; - - cp = findslash (where, cp - 1); - if (cp == NULL) - break; /* we're done */ - - new = (struct dir_to_build *) - xmalloc (sizeof (struct dir_to_build)); - new->dirpath = xmalloc (strlen (where)); - - /* If the user specified an absolute path for where, the - last path element we create should be the top-level - directory. */ - - if (cp > where) - { - strncpy (new->dirpath, where, cp - where); - new->dirpath[cp - where] = '\0'; - } - else - { - /* where should always be at least one character long. */ - assert (where[0] != '\0'); - strcpy (new->dirpath, "/"); - } - new->next = head; - head = new; - - /* If where consists of multiple pathname components, - then we want to just cd into it, without creating - directories or modifying CVS directories as we go. - In CVS 1.9 and earlier, the code actually does a - CVS_CHDIR up-front; I'm not going to try to go back - to that exact code but this is somewhat similar - in spirit. */ - if (where_orig != NULL - && cp - where < strlen (where_orig)) - { - new->repository = NULL; - new->just_chdir = 1; - continue; - } - - new->just_chdir = 0; - - /* Now figure out what repository directory to generate. - The most complete case would be something like this: - - The modules file contains - foo -d bar/baz quux - - The command issued was: - cvs co -d what/ever -N foo - - The results in the CVS/Repository files should be: - . -> (don't touch CVS/Repository) - (I think this case might be buggy currently) - what -> (don't touch CVS/Repository) - ever -> . (same as "cd what/ever; cvs co -N foo") - bar -> Emptydir (generated dir -- not in repos) - baz -> quux (finally!) */ - - if (strcmp (reposcopy, current_parsed_root->directory) == 0) - { - /* We can't walk up past CVSROOT. Instead, the - repository should be Emptydir. */ - new->repository = emptydir_name (); - } - else - { - /* It's a directory in the repository! */ - - 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", - reposcopy); - - *rp = '\0'; - new->repository = xmalloc (strlen (reposcopy) + 5); - (void) strcpy (new->repository, reposcopy); - - if (strcmp (reposcopy, current_parsed_root->directory) == 0) - { - /* Special case -- the repository name needs - to be "/path/to/repos/." (the trailing dot - is important). We might be able to get rid - of this after the we check out the other - code that handles repository names. */ - (void) strcat (new->repository, "/."); - } - } - } - - /* clean up */ - free (reposcopy); - - /* The top-level CVSADM directory should always be - current_parsed_root->directory. Create it, but only if WHERE is - relative. If WHERE is absolute, our current directory - may not have a thing to do with where the sources are - being checked out. If it does, build_dirs_and_chdir - will take care of creating adm files here. */ - /* FIXME: checking is_absolute (where) is a horrid kludge; - I suspect we probably can just skip the call to - build_one_dir whenever the -d command option was specified - to checkout. */ - - if (!isabsolute (where) && top_level_admin && m_type == CHECKOUT) - { - /* It may be argued that we shouldn't set any sticky - bits for the top-level repository. FIXME? */ - build_one_dir (current_parsed_root->directory, ".", argc <= 1); - -#ifdef SERVER_SUPPORT - /* We _always_ want to have a top-level admin - directory. If we're running in client/server mode, - send a "Clear-static-directory" command to make - sure it is created on the client side. (See 5.10 - in cvsclient.dvi to convince yourself that this is - OK.) If this is a duplicate command being sent, it - will be ignored on the client side. */ - - if (server_active) - server_clear_entstat (".", current_parsed_root->directory); -#endif - } - - - /* Build dirs on the path if necessary and leave us in the - bottom directory (where if where was specified) doesn't - contain a CVS subdir yet, but all the others contain - CVS and Entries.Static files */ - - if (build_dirs_and_chdir (head, argc <= 1) != 0) - { - error (0, 0, "ignoring module %s", omodule); - err = 1; - goto out; - } - - /* set up the repository (or make sure the old one matches) */ - if (!isfile (CVSADM)) - { - FILE *fp; - - 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, - m_type == CHECKOUT); - 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 (where, repository); -#endif - } - else - { - /* 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, tag, date, - - /* FIXME? This is a guess. If it is important - for nonbranch to be set correctly here I - think we need to write it one way now and - then rewrite it later via WriteTag, once - we've had a chance to call RCS_nodeisbranch - on each file. */ - 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) - { - error (0, 0, "existing repository %s does not match %s", - repos, repository); - error (0, 0, "ignoring module %s", omodule); - free (repos); - err = 1; - goto out; - } - free (repos); - } - } - - /* - * If we are going to be updating to stdout, we need to cd to the - * repository directory so the recursion processor can use the current - * directory as the place to find repository information - */ - if (pipeout) - { - if ( CVS_CHDIR (repository) < 0) - { - error (0, errno, "cannot chdir to %s", repository); - err = 1; - goto out; - } - which = W_REPOS; - if (tag != NULL && !tag_validated) - { - tag_check_valid (tag, argc - 1, argv + 1, 0, aflag, - repository); - tag_validated = 1; - } - } - else - { - which = W_LOCAL | W_REPOS; - if (tag != NULL && !tag_validated) - { - tag_check_valid (tag, argc - 1, argv + 1, 0, aflag, - repository); - tag_validated = 1; - } - } - - if (tag != NULL || date != NULL || join_rev1 != NULL) - which |= W_ATTIC; - - if (! join_tags_validated) - { - if (join_rev1 != NULL) - tag_check_valid_join (join_rev1, argc - 1, argv + 1, 0, aflag, - repository); - if (join_rev2 != NULL) - tag_check_valid_join (join_rev2, argc - 1, argv + 1, 0, aflag, - repository); - join_tags_validated = 1; - } - - /* - * if we are going to be recursive (building dirs), go ahead and call the - * update recursion processor. We will be recursive unless either local - * only was specified, or we were passed arguments - */ - if (!(local_specified || argc > 1)) - { - if (!pipeout) - history_write (m_type == CHECKOUT ? 'O' : 'E', preload_update_dir, - history_name, where, repository); - err += do_update (0, (char **) NULL, options, tag, date, - force_tag_match, 0 /* !local */ , - 1 /* update -d */ , aflag, checkout_prune_dirs, - pipeout, which, join_rev1, join_rev2, - preload_update_dir, pull_template, repository); - goto out; - } - - if (!pipeout) - { - int i; - List *entries; - - /* we are only doing files, so register them */ - entries = Entries_Open (0, NULL); - for (i = 1; i < argc; i++) - { - char *line; - Vers_TS *vers; - struct file_info finfo; - - memset (&finfo, 0, sizeof finfo); - finfo.file = argv[i]; - /* Shouldn't be used, so set to arbitrary value. */ - finfo.update_dir = NULL; - finfo.fullname = argv[i]; - finfo.repository = repository; - finfo.entries = entries; - /* The rcs slot is needed to get the options from the RCS - file */ - finfo.rcs = RCS_parse (finfo.file, repository); - - vers = Version_TS (&finfo, options, tag, date, - force_tag_match, 0); - if (vers->ts_user == NULL) - { - line = xmalloc (strlen (finfo.file) + 15); - (void) sprintf (line, "Initial %s", finfo.file); - Register (entries, finfo.file, - vers->vn_rcs ? vers->vn_rcs : "0", - line, vers->options, vers->tag, - vers->date, (char *) 0); - free (line); - } - freevers_ts (&vers); - freercsnode (&finfo.rcs); - } - - Entries_Close (entries); - } - - /* Don't log "export", just regular "checkouts" */ - 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 (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, pull_template, repository); -out: - free (preload_update_dir); - preload_update_dir = oldupdate; - free (where); - free (repository); - return (err); -} - -static char * -findslash (start, p) - char *start; - char *p; -{ - for (;;) - { - if (*p == '/') return p; - if (p == start) break; - --p; - } - return NULL; -} - -/* Return a newly malloc'd string containing a pathname for CVSNULLREPOS, - and make sure that it exists. If there is an error creating the - directory, give a fatal error. Otherwise, the directory is guaranteed - to exist when we return. */ -char * -emptydir_name () -{ - char *repository; - - repository = xmalloc (strlen (current_parsed_root->directory) - + sizeof (CVSROOTADM) - + sizeof (CVSNULLREPOS) - + 3); - (void) sprintf (repository, "%s/%s/%s", current_parsed_root->directory, - CVSROOTADM, CVSNULLREPOS); - if (!isfile (repository)) - { - mode_t omask; - omask = umask (cvsumask); - if (CVS_MKDIR (repository, 0777) < 0) - error (1, errno, "cannot create %s", repository); - (void) umask (omask); - } - return repository; -} - -/* Build all the dirs along the path to DIRS with CVS subdirs with appropriate - * repositories. If DIRS->repository is NULL or the directory already exists, - * do not create a CVSADM directory for that subdirectory; just CVS_CHDIR into - * it. Frees all storage used by DIRS. - * - * ASSUMPTIONS - * 1. Parent directories will be listed in DIRS before their children. - * 2. At most a single directory will need to be changed at one time. In - * other words, if we are in /a/b/c, and our final destination is - * /a/b/c/d/e/f, then we will build d, then d/e, then d/e/f. - * - * INPUTS - * dirs Simple list composed of dir_to_build structures, listing - * information about directories to build. - * sticky Passed to build_one_dir to tell it whether there are any sticky - * tags or dates to be concerned with. - * - * RETURNS - * 1 on error, 0 otherwise. - * - * ERRORS - * The only nonfatal error this function may return is if the CHDIR fails. - */ -static int -build_dirs_and_chdir (dirs, sticky) - struct dir_to_build *dirs; - int sticky; -{ - int retval = 0; - struct dir_to_build *nextdir; - - while (dirs != NULL) - { - const char *dir = last_component (dirs->dirpath); - - if (!dirs->just_chdir) - { - mkdir_if_needed (dir); - Subdir_Register (NULL, NULL, dir); - } - - if (CVS_CHDIR (dir) < 0) - { - error (0, errno, "cannot chdir to %s", dir); - retval = 1; - goto out; - } - if (dirs->repository != NULL) - { - build_one_dir (dirs->repository, dirs->dirpath, sticky); - free (dirs->repository); - } - nextdir = dirs->next; - free (dirs->dirpath); - free (dirs); - dirs = nextdir; - } - - 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/classify.c b/contrib/cvs/src/classify.c deleted file mode 100644 index 28d7263..0000000 --- a/contrib/cvs/src/classify.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include "cvs.h" - -static void sticky_ck PROTO ((struct file_info *finfo, int aflag, - Vers_TS * vers)); - - - -static inline int keywords_may_change PROTO ((int aflag, Vers_TS * vers)); -static inline int -keywords_may_change (aflag, vers) - int aflag; - Vers_TS * vers; -{ - int retval; - - if (/* Options are different... */ - strcmp (vers->entdata->options, vers->options) - /* ...or... */ - || (/* ...clearing stickies... */ - aflag - /* ...and... */ - && (/* ...there used to be a tag which subs in Name keys... */ - (vers->entdata->tag && !isdigit (vers->entdata->tag[0]) - && vers->tag && !isdigit (vers->tag[0]) - && strcmp (vers->entdata->tag, vers->tag)) - /* ...or there used to be a keyword mode which may be - * changed by -A... - */ - || (strlen (vers->entdata->options) - && strcmp (vers->entdata->options, vers->options) - && strcmp (vers->entdata->options, "-kkv") - && strcmp (vers->entdata->options, "-kb")))) - /* ...or... */ - || (/* ...this is not commit... */ - strcmp (cvs_cmd_name, "commit") - /* ...and... */ - && (/* ...the tag is changing in a way that affects Name keys... */ - (vers->entdata->tag && vers->tag - && strcmp (vers->entdata->tag, vers->tag) - && !(isdigit (vers->entdata->tag[0]) - && isdigit (vers->entdata->tag[0]))) - || (!vers->entdata->tag && vers->tag - && !isdigit (vers->tag[0]))))) - retval = 1; - else - retval = 0; - - return retval; -} - - - -/* - * Classify the state of a file - */ -Ctype -Classify_File (finfo, tag, date, options, force_tag_match, aflag, versp, - pipeout) - struct file_info *finfo; - char *tag; - char *date; - - /* Keyword expansion options. Can be either NULL or "" to - indicate none are specified here. */ - char *options; - - int force_tag_match; - int aflag; - Vers_TS **versp; - int pipeout; -{ - Vers_TS *vers; - Ctype ret; - - /* get all kinds of good data about the file */ - vers = Version_TS (finfo, options, tag, date, - force_tag_match, 0); - - if (vers->vn_user == NULL) - { - /* No entry available, ts_rcs is invalid */ - if (vers->vn_rcs == NULL) - { - /* there is no RCS file either */ - if (vers->ts_user == NULL) - { - /* there is no user file */ - /* FIXME: Why do we skip this message if vers->tag or - vers->date is set? It causes "cvs update -r tag98 foo" - to silently do nothing, which is seriously confusing - behavior. "cvs update foo" gives this message, which - is what I would expect. */ - if (!force_tag_match || !(vers->tag || vers->date)) - if (!really_quiet) - error (0, 0, "nothing known about %s", finfo->fullname); - ret = T_UNKNOWN; - } - else - { - /* there is a user file */ - /* FIXME: Why do we skip this message if vers->tag or - vers->date is set? It causes "cvs update -r tag98 foo" - to silently do nothing, which is seriously confusing - behavior. "cvs update foo" gives this message, which - is what I would expect. */ - if (!force_tag_match || !(vers->tag || vers->date)) - if (!really_quiet) - error (0, 0, "use `%s add' to create an entry for %s", - program_name, finfo->fullname); - ret = T_UNKNOWN; - } - } - else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) - { - /* there is an RCS file, but it's dead */ - if (vers->ts_user == NULL) - ret = T_UPTODATE; - else - { - error (0, 0, "use `%s add' to create an entry for %s", - program_name, finfo->fullname); - ret = T_UNKNOWN; - } - } - else if (!pipeout && vers->ts_user && No_Difference (finfo, vers)) - { - /* the files were different so it is a conflict */ - if (!really_quiet) - error (0, 0, "move away %s; it is in the way", - finfo->fullname); - ret = T_CONFLICT; - } - else - /* no user file or no difference, just checkout */ - ret = T_CHECKOUT; - } - else if (strcmp (vers->vn_user, "0") == 0) - { - /* An entry for a new-born file; ts_rcs is dummy */ - - if (vers->ts_user == NULL) - { - if (pipeout) - { - ret = T_CHECKOUT; - } - else - { - /* - * There is no user file, but there should be one; remove the - * entry - */ - if (!really_quiet) - error (0, 0, "warning: new-born %s has disappeared", - finfo->fullname); - ret = T_REMOVE_ENTRY; - } - } - else if (vers->vn_rcs == NULL || - RCS_isdead (vers->srcfile, vers->vn_rcs)) - /* No RCS file or RCS file revision is dead */ - ret = T_ADDED; - else - { - if (pipeout) - { - ret = T_CHECKOUT; - } - else - { - if (vers->srcfile->flags & INATTIC - && vers->srcfile->flags & VALID) - { - /* This file has been added on some branch other than - the one we are looking at. In the branch we are - looking at, the file was already valid. */ - if (!really_quiet) - error (0, 0, - "conflict: %s has been added, but already exists", - finfo->fullname); - } - else - { - /* - * There is an RCS file, so someone else must have checked - * one in behind our back; conflict - */ - if (!really_quiet) - error (0, 0, - "conflict: %s created independently by second party", - finfo->fullname); - } - ret = T_CONFLICT; - } - } - } - else if (vers->vn_user[0] == '-') - { - /* An entry for a removed file, ts_rcs is invalid */ - - if (vers->ts_user == NULL) - { - /* There is no user file (as it should be) */ - - if (vers->vn_rcs == NULL - || RCS_isdead (vers->srcfile, vers->vn_rcs)) - { - - /* - * There is no RCS file; this is all-right, but it has been - * removed independently by a second party; remove the entry - */ - ret = T_REMOVE_ENTRY; - } - else if (strcmp (vers->vn_rcs, vers->vn_user + 1) == 0) - /* - * The RCS file is the same version as the user file was, and - * that's OK; remove it - */ - ret = T_REMOVED; - else if (pipeout) - /* - * The RCS file doesn't match the user's file, but it doesn't - * matter in this case - */ - ret = T_NEEDS_MERGE; - else - { - - /* - * The RCS file is a newer version than the removed user file - * and this is definitely not OK; make it a conflict. - */ - if (!really_quiet) - error (0, 0, - "conflict: removed %s was modified by second party", - finfo->fullname); - ret = T_CONFLICT; - } - } - else - { - /* The user file shouldn't be there */ - if (!really_quiet) - error (0, 0, "%s should be removed and is still there", - finfo->fullname); - ret = T_REMOVED; - } - } - else - { - /* A normal entry, TS_Rcs is valid */ - if (vers->vn_rcs == NULL || RCS_isdead (vers->srcfile, vers->vn_rcs)) - { - /* There is no RCS file */ - - if (vers->ts_user == NULL) - { - /* There is no user file, so just remove the entry */ - if (!really_quiet) - error (0, 0, "warning: %s is not (any longer) pertinent", - finfo->fullname); - ret = T_REMOVE_ENTRY; - } - else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) - { - - /* - * The user file is still unmodified, so just remove it from - * the entry list - */ - if (!really_quiet) - error (0, 0, "%s is no longer in the repository", - finfo->fullname); - ret = T_REMOVE_ENTRY; - } - else if (No_Difference (finfo, vers)) - { - /* they are different -> conflict */ - if (!really_quiet) - error (0, 0, - "conflict: %s is modified but no longer in the repository", - finfo->fullname); - ret = T_CONFLICT; - } - else - { - /* they weren't really different */ - if (!really_quiet) - error (0, 0, - "warning: %s is not (any longer) pertinent", - finfo->fullname); - ret = T_REMOVE_ENTRY; - } - } - else if (strcmp (vers->vn_rcs, vers->vn_user) == 0) - { - /* The RCS file is the same version as the user file */ - - if (vers->ts_user == NULL) - { - - /* - * There is no user file, so note that it was lost and - * extract a new version - */ - /* Comparing the cvs_cmd_name against "update", in - addition to being an ugly way to operate, means - that this message does not get printed by the - server. That might be considered just a straight - bug, although there is one subtlety: that case also - gets hit when a patch fails and the client fetches - a file. I'm not sure there is currently any way - for the server to distinguish those two cases. */ - if (strcmp (cvs_cmd_name, "update") == 0) - if (!really_quiet) - error (0, 0, "warning: %s was lost", finfo->fullname); - ret = T_CHECKOUT; - } - else if (!strcmp (vers->ts_user, - vers->ts_conflict - ? vers->ts_conflict : vers->ts_rcs)) - { - - /* - * The user file is still unmodified, so nothing special at - * all to do -- no lists updated, unless the sticky -k option - * has changed. If the sticky tag has changed, we just need - * to re-register the entry - */ - /* TODO: decide whether we need to check file permissions - for a mismatch, and return T_CONFLICT if so. */ - if (keywords_may_change (aflag, vers)) - ret = T_PATCH; - else if (vers->ts_conflict) - ret = T_CONFLICT; - else - { - ret = T_UPTODATE; - sticky_ck (finfo, aflag, vers); - } - } - else if (No_Difference (finfo, vers)) - { - - /* - * they really are different; modified if we aren't - * changing any sticky -k options, else needs merge - */ -#ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED - if (strcmp (vers->entdata->options ? - vers->entdata->options : "", vers->options) == 0) - ret = T_MODIFIED; - else - ret = T_NEEDS_MERGE; -#else - /* Files with conflict markers and new timestamps fall through - * here, but they need to. T_CONFLICT is an error in - * commit_fileproc, whereas T_CONFLICT with conflict markers - * is caught but only warned about. Similarly, update_fileproc - * currently reregisters a file that was conflicted but lost - * its markers. - */ - ret = T_MODIFIED; - sticky_ck (finfo, aflag, vers); -#endif - } - else if (strcmp (vers->entdata->options ? - vers->entdata->options : "", vers->options) != 0) - { - /* file has not changed; check out if -k changed */ - ret = T_CHECKOUT; - } - else - { - - /* - * else -> note that No_Difference will Register the - * file already for us, using the new tag/date. This - * is the desired behaviour - */ - ret = T_UPTODATE; - } - } - else - { - /* The RCS file is a newer version than the user file */ - - if (vers->ts_user == NULL) - { - /* There is no user file, so just get it */ - - /* See comment at other "update" compare, for more - thoughts on this comparison. */ - if (strcmp (cvs_cmd_name, "update") == 0) - if (!really_quiet) - error (0, 0, "warning: %s was lost", finfo->fullname); - ret = T_CHECKOUT; - } - else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) - - /* - * The user file is still unmodified, so just get it as well - */ - ret = T_PATCH; - else if (No_Difference (finfo, vers)) - /* really modified, needs to merge */ - ret = T_NEEDS_MERGE; - else - ret = T_PATCH; - } - } - - /* free up the vers struct, or just return it */ - if (versp != (Vers_TS **) NULL) - *versp = vers; - else - freevers_ts (&vers); - - /* return the status of the file */ - return (ret); -} - -static void -sticky_ck (finfo, aflag, vers) - struct file_info *finfo; - int aflag; - Vers_TS *vers; -{ - if (aflag || vers->tag || vers->date) - { - char *enttag = vers->entdata->tag; - char *entdate = vers->entdata->date; - - if ((enttag && vers->tag && strcmp (enttag, vers->tag)) || - ((enttag && !vers->tag) || (!enttag && vers->tag)) || - (entdate && vers->date && strcmp (entdate, vers->date)) || - ((entdate && !vers->date) || (!entdate && vers->date))) - { - Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs, - vers->options, vers->tag, vers->date, vers->ts_conflict); - -#ifdef SERVER_SUPPORT - if (server_active) - { - /* We need to update the entries line on the client side. - It is possible we will later update it again via - server_updated or some such, but that is OK. */ - server_update_entries - (finfo->file, finfo->update_dir, finfo->repository, - strcmp (vers->ts_rcs, vers->ts_user) == 0 ? - SERVER_UPDATED : SERVER_MERGED); - } -#endif - } - } -} diff --git a/contrib/cvs/src/client.c b/contrib/cvs/src/client.c deleted file mode 100644 index 1c8a5d0..0000000 --- a/contrib/cvs/src/client.c +++ /dev/null @@ -1,5948 +0,0 @@ -/* CVS client-related stuff. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -/* - * $FreeBSD$ - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include <assert.h> -#include "cvs.h" -#include "getline.h" -#include "edit.h" -#include "buffer.h" -#include "savecwd.h" - -#ifdef CLIENT_SUPPORT - -# include "md5.h" - -# if defined(AUTH_CLIENT_SUPPORT) || defined(HAVE_KERBEROS) || defined(HAVE_GSSAPI) || defined(SOCK_ERRNO) || defined(SOCK_STRERROR) -# ifdef HAVE_WINSOCK_H -# include <winsock.h> -# else /* No winsock.h */ -# include <sys/socket.h> -# include <netinet/in.h> -# include <arpa/inet.h> -# include <netdb.h> -# endif /* No winsock.h */ -# endif - -/* If SOCK_ERRNO is defined, then send()/recv() and other socket calls - do not set errno, but that this macro should be used to obtain an - error code. This probably doesn't make sense unless - NO_SOCKET_TO_FD is also defined. */ -# ifndef SOCK_ERRNO -# define SOCK_ERRNO errno -# endif - -/* If SOCK_STRERROR is defined, then the error codes returned by - socket operations are not known to strerror, and this macro must be - used instead to convert those error codes to strings. */ -# ifndef SOCK_STRERROR -# define SOCK_STRERROR strerror - -# if STDC_HEADERS -# include <string.h> -# endif - -# ifndef strerror -extern char *strerror (); -# endif -# endif /* ! SOCK_STRERROR */ - -# if HAVE_KERBEROS - -# include <krb.h> - -extern char *krb_realmofhost (); -# ifndef HAVE_KRB_GET_ERR_TEXT -# define krb_get_err_text(status) krb_err_txt[status] -# endif /* HAVE_KRB_GET_ERR_TEXT */ - -/* Information we need if we are going to use Kerberos encryption. */ -static C_Block kblock; -static Key_schedule sched; - -# endif /* HAVE_KERBEROS */ - -# ifdef HAVE_GSSAPI - -# include "xgssapi.h" - -/* This is needed for GSSAPI encryption. */ -static gss_ctx_id_t gcontext; - -static int connect_to_gserver PROTO((cvsroot_t *, int, struct hostent *)); - -# endif /* HAVE_GSSAPI */ - - - -/* Keep track of any paths we are sending for Max-dotdot so that we can verify - * that uplevel paths coming back form the server are valid. - * - * FIXME: The correct way to do this is probably provide some sort of virtual - * path map on the client side. This would be generic enough to be applied to - * absolute paths supplied by the user too. - */ -static List *uppaths = NULL; - - - -static void add_prune_candidate PROTO((const char *)); - -/* All the commands. */ -int add PROTO((int argc, char **argv)); -int admin PROTO((int argc, char **argv)); -int checkout PROTO((int argc, char **argv)); -int commit PROTO((int argc, char **argv)); -int diff PROTO((int argc, char **argv)); -int history PROTO((int argc, char **argv)); -int import PROTO((int argc, char **argv)); -int cvslog PROTO((int argc, char **argv)); -int patch PROTO((int argc, char **argv)); -int release PROTO((int argc, char **argv)); -int cvsremove PROTO((int argc, char **argv)); -int rtag PROTO((int argc, char **argv)); -int status PROTO((int argc, char **argv)); -int tag PROTO((int argc, char **argv)); -int update PROTO((int argc, char **argv)); - -/* All the response handling functions. */ -static void handle_ok PROTO((char *, int)); -static void handle_error PROTO((char *, int)); -static void handle_valid_requests PROTO((char *, int)); -static void handle_checked_in PROTO((char *, int)); -static void handle_new_entry PROTO((char *, int)); -static void handle_checksum PROTO((char *, int)); -static void handle_copy_file PROTO((char *, int)); -static void handle_updated PROTO((char *, int)); -static void handle_merged PROTO((char *, int)); -static void handle_patched PROTO((char *, int)); -static void handle_rcs_diff PROTO((char *, int)); -static void handle_removed PROTO((char *, int)); -static void handle_remove_entry PROTO((char *, int)); -static void handle_set_static_directory PROTO((char *, int)); -static void handle_clear_static_directory PROTO((char *, int)); -static void handle_set_sticky PROTO((char *, int)); -static void handle_clear_sticky PROTO((char *, int)); -static void handle_module_expansion PROTO((char *, int)); -static void handle_wrapper_rcs_option PROTO((char *, int)); -static void handle_m PROTO((char *, int)); -static void handle_e PROTO((char *, int)); -static void handle_f PROTO((char *, int)); -static void handle_notified PROTO((char *, int)); - -static size_t try_read_from_server PROTO ((char *, size_t)); - -static void auth_server PROTO ((cvsroot_t *, struct buffer *, struct buffer *, - int, int, struct hostent *)); - -/* We need to keep track of the list of directories we've sent to the - server. This list, along with the current CVSROOT, will help us - decide which command-line arguments to send. */ -List *dirs_sent_to_server = NULL; - -static int is_arg_a_parent_or_listed_dir PROTO((Node *, void *)); - -static int -is_arg_a_parent_or_listed_dir (n, d) - Node *n; - void *d; -{ - char *directory = n->key; /* name of the dir sent to server */ - char *this_argv_elem = xstrdup (d); /* this argv element */ - int retval; - - /* Say we should send this argument if the argument matches the - beginning of a directory name sent to the server. This way, - the server will know to start at the top of that directory - hierarchy and descend. */ - - strip_trailing_slashes (this_argv_elem); - if (strncmp (directory, this_argv_elem, strlen (this_argv_elem)) == 0) - retval = 1; - else - retval = 0; - - free (this_argv_elem); - return retval; -} - -static int arg_should_not_be_sent_to_server PROTO((char *)); - -/* Return nonzero if this argument should not be sent to the - server. */ - -static int -arg_should_not_be_sent_to_server (arg) - char *arg; -{ - /* Decide if we should send this directory name to the server. We - should always send argv[i] if: - - 1) the list of directories sent to the server is empty (as it - will be for checkout, etc.). - - 2) the argument is "." - - 3) the argument is a file in the cwd and the cwd is checked out - from the current root - - 4) the argument lies within one of the paths in - dirs_sent_to_server. - - */ - - if (list_isempty (dirs_sent_to_server)) - return 0; /* always send it */ - - if (strcmp (arg, ".") == 0) - return 0; /* always send it */ - - /* We should send arg if it is one of the directories sent to the - server or the parent of one; this tells the server to descend - the hierarchy starting at this level. */ - if (isdir (arg)) - { - if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir, arg)) - return 0; - - /* If arg wasn't a parent, we don't know anything about it (we - would have seen something related to it during the - send_files phase). Don't send it. */ - return 1; - } - - /* Try to decide whether we should send arg to the server by - checking the contents of the corresponding CVSADM directory. */ - { - char *t, *root_string; - cvsroot_t *this_root = NULL; - - /* Calculate "dirname arg" */ - for (t = arg + strlen (arg) - 1; t >= arg; t--) - { - if (ISDIRSEP(*t)) - break; - } - - /* Now we're either poiting to the beginning of the - string, or we found a path separator. */ - if (t >= arg) - { - /* Found a path separator. */ - char c = *t; - *t = '\0'; - - /* First, check to see if we sent this directory to the - server, because it takes less time than actually - opening the stuff in the CVSADM directory. */ - if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir, - arg)) - { - *t = c; /* make sure to un-truncate the arg */ - return 0; - } - - /* Since we didn't find it in the list, check the CVSADM - files on disk. */ - this_root = Name_Root (arg, (char *) NULL); - root_string = this_root->original; - *t = c; - } - else - { - /* We're at the beginning of the string. Look at the - CVSADM files in cwd. */ - if (CVSroot_cmdline) - root_string = CVSroot_cmdline; - else - { - this_root = Name_Root ((char *) NULL, (char *) NULL); - root_string = this_root->original; - } - } - - /* Now check the value for root. */ - if (CVSroot_cmdline == NULL && - root_string && current_parsed_root - && (strcmp (root_string, current_parsed_root->original) != 0)) - { - /* Don't send this, since the CVSROOTs don't match. */ - if (this_root) free_cvsroot_t (this_root); - return 1; - } - if (this_root) free_cvsroot_t (this_root); - } - - /* OK, let's send it. */ - return 0; -} - - - -#endif /* CLIENT_SUPPORT */ - - - -#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT) - -/* Shared with server. */ - -/* - * Return a malloc'd, '\0'-terminated string - * corresponding to the mode in SB. - */ -char * -#ifdef __STDC__ -mode_to_string (mode_t mode) -#else /* ! __STDC__ */ -mode_to_string (mode) - mode_t mode; -#endif /* __STDC__ */ -{ - char buf[18], u[4], g[4], o[4]; - int i; - - i = 0; - if (mode & S_IRUSR) u[i++] = 'r'; - if (mode & S_IWUSR) u[i++] = 'w'; - if (mode & S_IXUSR) u[i++] = 'x'; - u[i] = '\0'; - - i = 0; - if (mode & S_IRGRP) g[i++] = 'r'; - if (mode & S_IWGRP) g[i++] = 'w'; - if (mode & S_IXGRP) g[i++] = 'x'; - g[i] = '\0'; - - i = 0; - if (mode & S_IROTH) o[i++] = 'r'; - if (mode & S_IWOTH) o[i++] = 'w'; - if (mode & S_IXOTH) o[i++] = 'x'; - o[i] = '\0'; - - sprintf(buf, "u=%s,g=%s,o=%s", u, g, o); - return xstrdup(buf); -} - -/* - * Change mode of FILENAME to MODE_STRING. - * Returns 0 for success or errno code. - * If RESPECT_UMASK is set, then honor the umask. - */ -int -change_mode (filename, mode_string, respect_umask) - char *filename; - char *mode_string; - int respect_umask; -{ -#ifdef CHMOD_BROKEN - char *p; - int writeable = 0; - - /* We can only distinguish between - 1) readable - 2) writeable - 3) Picasso's "Blue Period" - We handle the first two. */ - p = mode_string; - while (*p != '\0') - { - if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=') - { - char *q = p + 2; - while (*q != ',' && *q != '\0') - { - if (*q == 'w') - writeable = 1; - ++q; - } - } - /* Skip to the next field. */ - while (*p != ',' && *p != '\0') - ++p; - if (*p == ',') - ++p; - } - - /* xchmod honors the umask for us. In the !respect_umask case, we - don't try to cope with it (probably to handle that well, the server - needs to deal with modes in data structures, rather than via the - modes in temporary files). */ - xchmod (filename, writeable); - return 0; - -#else /* ! CHMOD_BROKEN */ - - char *p; - mode_t mode = 0; - mode_t oumask; - - p = mode_string; - while (*p != '\0') - { - if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=') - { - int can_read = 0, can_write = 0, can_execute = 0; - char *q = p + 2; - while (*q != ',' && *q != '\0') - { - if (*q == 'r') - can_read = 1; - else if (*q == 'w') - can_write = 1; - else if (*q == 'x') - can_execute = 1; - ++q; - } - if (p[0] == 'u') - { - if (can_read) - mode |= S_IRUSR; - if (can_write) - mode |= S_IWUSR; - if (can_execute) - mode |= S_IXUSR; - } - else if (p[0] == 'g') - { - if (can_read) - mode |= S_IRGRP; - if (can_write) - mode |= S_IWGRP; - if (can_execute) - mode |= S_IXGRP; - } - else if (p[0] == 'o') - { - if (can_read) - mode |= S_IROTH; - if (can_write) - mode |= S_IWOTH; - if (can_execute) - mode |= S_IXOTH; - } - } - /* Skip to the next field. */ - while (*p != ',' && *p != '\0') - ++p; - if (*p == ',') - ++p; - } - - if (respect_umask) - { - oumask = umask (0); - (void) umask (oumask); - mode &= ~oumask; - } - - if (chmod (filename, mode) < 0) - return errno; - return 0; -#endif /* ! CHMOD_BROKEN */ -} - -#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ - -#ifdef CLIENT_SUPPORT - -int client_prune_dirs; - -static List *ignlist = (List *) NULL; - -/* Buffer to write to the server. */ -static struct buffer *to_server; - -/* Buffer used to read from the server. */ -static struct buffer *from_server; - - -/* We want to be able to log data sent between us and the server. We - do it using log buffers. Each log buffer has another buffer which - handles the actual I/O, and a file to log information to. - - This structure is the closure field of a log buffer. */ - -struct log_buffer -{ - /* The underlying buffer. */ - struct buffer *buf; - /* The file to log information to. */ - FILE *log; -}; - -static struct buffer *log_buffer_initialize - PROTO((struct buffer *, FILE *, int, void (*) (struct buffer *))); -static int log_buffer_input PROTO((void *, char *, int, int, int *)); -static int log_buffer_output PROTO((void *, const char *, int, int *)); -static int log_buffer_flush PROTO((void *)); -static int log_buffer_block PROTO((void *, int)); -static int log_buffer_shutdown PROTO((struct buffer *)); - -/* Create a log buffer. */ - -static struct buffer * -log_buffer_initialize (buf, fp, input, memory) - struct buffer *buf; - FILE *fp; - int input; - void (*memory) PROTO((struct buffer *)); -{ - struct log_buffer *n; - - n = (struct log_buffer *) xmalloc (sizeof *n); - n->buf = buf; - n->log = fp; - return buf_initialize (input ? log_buffer_input : NULL, - input ? NULL : log_buffer_output, - input ? NULL : log_buffer_flush, - log_buffer_block, - log_buffer_shutdown, - memory, - n); -} - -/* The input function for a log buffer. */ - -static int -log_buffer_input (closure, data, need, size, got) - void *closure; - char *data; - int need; - int size; - int *got; -{ - struct log_buffer *lb = (struct log_buffer *) closure; - int status; - size_t n_to_write; - - if (lb->buf->input == NULL) - abort (); - - status = (*lb->buf->input) (lb->buf->closure, data, need, size, got); - if (status != 0) - return status; - - if (*got > 0) - { - n_to_write = *got; - if (fwrite (data, 1, n_to_write, lb->log) != n_to_write) - error (0, errno, "writing to log file"); - } - - return 0; -} - -/* The output function for a log buffer. */ - -static int -log_buffer_output (closure, data, have, wrote) - void *closure; - const char *data; - int have; - int *wrote; -{ - struct log_buffer *lb = (struct log_buffer *) closure; - int status; - size_t n_to_write; - - if (lb->buf->output == NULL) - abort (); - - status = (*lb->buf->output) (lb->buf->closure, data, have, wrote); - if (status != 0) - return status; - - if (*wrote > 0) - { - n_to_write = *wrote; - if (fwrite (data, 1, n_to_write, lb->log) != n_to_write) - error (0, errno, "writing to log file"); - } - - return 0; -} - -/* The flush function for a log buffer. */ - -static int -log_buffer_flush (closure) - void *closure; -{ - struct log_buffer *lb = (struct log_buffer *) closure; - - if (lb->buf->flush == NULL) - abort (); - - /* We don't really have to flush the log file here, but doing it - will let tail -f on the log file show what is sent to the - network as it is sent. */ - if (fflush (lb->log) != 0) - error (0, errno, "flushing log file"); - - return (*lb->buf->flush) (lb->buf->closure); -} - -/* The block function for a log buffer. */ - -static int -log_buffer_block (closure, block) - void *closure; - int block; -{ - struct log_buffer *lb = (struct log_buffer *) closure; - - if (block) - return set_block (lb->buf); - else - return set_nonblock (lb->buf); -} - -/* The shutdown function for a log buffer. */ - -static int -log_buffer_shutdown (buf) - struct buffer *buf; -{ - struct log_buffer *lb = (struct log_buffer *) buf->closure; - int retval; - - retval = buf_shutdown (lb->buf); - if (fclose (lb->log) < 0) - error (0, errno, "closing log file"); - return retval; -} - -#ifdef NO_SOCKET_TO_FD - -/* Under certain circumstances, we must communicate with the server - via a socket using send() and recv(). This is because under some - operating systems (OS/2 and Windows 95 come to mind), a socket - cannot be converted to a file descriptor -- it must be treated as a - socket and nothing else. - - We may also need to deal with socket routine error codes differently - in these cases. This is handled through the SOCK_ERRNO and - SOCK_STRERROR macros. */ - -/* These routines implement a buffer structure which uses send and - recv. The buffer is always in blocking mode so we don't implement - the block routine. */ - -/* Note that it is important that these routines always handle errors - internally and never return a positive errno code, since it would in - general be impossible for the caller to know in general whether any - error code came from a socket routine (to decide whether to use - SOCK_STRERROR or simply strerror to print an error message). */ - -/* We use an instance of this structure as the closure field. */ - -struct socket_buffer -{ - /* The socket number. */ - int socket; -}; - -static struct buffer *socket_buffer_initialize - PROTO ((int, int, void (*) (struct buffer *))); -static int socket_buffer_input PROTO((void *, char *, int, int, int *)); -static int socket_buffer_output PROTO((void *, const char *, int, int *)); -static int socket_buffer_flush PROTO((void *)); -static int socket_buffer_shutdown PROTO((struct buffer *)); - - - -/* Create a buffer based on a socket. */ - -static struct buffer * -socket_buffer_initialize (socket, input, memory) - int socket; - int input; - void (*memory) PROTO((struct buffer *)); -{ - struct socket_buffer *n; - - n = (struct socket_buffer *) xmalloc (sizeof *n); - n->socket = socket; - return buf_initialize (input ? socket_buffer_input : NULL, - input ? NULL : socket_buffer_output, - input ? NULL : socket_buffer_flush, - (int (*) PROTO((void *, int))) NULL, - socket_buffer_shutdown, - memory, - n); -} - - - -/* The buffer input function for a buffer built on a socket. */ - -static int -socket_buffer_input (closure, data, need, size, got) - void *closure; - char *data; - int need; - int size; - int *got; -{ - struct socket_buffer *sb = (struct socket_buffer *) closure; - int nbytes; - - /* I believe that the recv function gives us exactly the semantics - we want. If there is a message, it returns immediately with - whatever it could get. If there is no message, it waits until - one comes in. In other words, it is not like read, which in - blocking mode normally waits until all the requested data is - available. */ - - *got = 0; - - do - { - - /* Note that for certain (broken?) networking stacks, like - VMS's UCX (not sure what version, problem reported with - recv() in 1997), and (according to windows-NT/config.h) - Windows NT 3.51, we must call recv or send with a - moderately sized buffer (say, less than 200K or something), - or else there may be network errors (somewhat hard to - produce, e.g. WAN not LAN or some such). buf_read_data - makes sure that we only recv() BUFFER_DATA_SIZE bytes at - a time. */ - - nbytes = recv (sb->socket, data, size, 0); - if (nbytes < 0) - error (1, 0, "reading from server: %s", SOCK_STRERROR (SOCK_ERRNO)); - if (nbytes == 0) - { - /* End of file (for example, the server has closed - the connection). If we've already read something, we - just tell the caller about the data, not about the end of - file. If we've read nothing, we return end of file. */ - if (*got == 0) - return -1; - else - return 0; - } - need -= nbytes; - size -= nbytes; - data += nbytes; - *got += nbytes; - } - while (need > 0); - - return 0; -} - - - -/* The buffer output function for a buffer built on a socket. */ - -static int -socket_buffer_output (closure, data, have, wrote) - void *closure; - const char *data; - int have; - int *wrote; -{ - struct socket_buffer *sb = (struct socket_buffer *) closure; - - *wrote = have; - - /* See comment in socket_buffer_input regarding buffer size we pass - to send and recv. */ - -#ifdef SEND_NEVER_PARTIAL - /* If send() never will produce a partial write, then just do it. This - is needed for systems where its return value is something other than - the number of bytes written. */ - if (send (sb->socket, data, have, 0) < 0) - error (1, 0, "writing to server socket: %s", SOCK_STRERROR (SOCK_ERRNO)); -#else - while (have > 0) - { - int nbytes; - - nbytes = send (sb->socket, data, have, 0); - if (nbytes < 0) - error (1, 0, "writing to server socket: %s", SOCK_STRERROR (SOCK_ERRNO)); - - have -= nbytes; - data += nbytes; - } -#endif - - return 0; -} - - - -/* The buffer flush function for a buffer built on a socket. */ - -/*ARGSUSED*/ -static int -socket_buffer_flush (closure) - void *closure; -{ - /* Nothing to do. Sockets are always flushed. */ - return 0; -} - - - -static int -socket_buffer_shutdown (buf) - struct buffer *buf; -{ - struct socket_buffer *n = (struct socket_buffer *) buf->closure; - char tmp; - - /* no need to flush children of an endpoint buffer here */ - - if (buf->input) - { - int err = 0; - if (! buf_empty_p (buf) - || (err = recv (n->socket, &tmp, 1, 0)) > 0) - error (0, 0, "dying gasps from %s unexpected", current_parsed_root->hostname); - else if (err == -1) - error (0, 0, "reading from %s: %s", current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO)); - - /* shutdown() socket */ -# ifdef SHUTDOWN_SERVER - if (current_parsed_root->method != server_method) -# endif - if (shutdown (n->socket, 0) < 0) - { - error (1, 0, "shutting down server socket: %s", SOCK_STRERROR (SOCK_ERRNO)); - } - - buf->input = NULL; - } - else if (buf->output) - { - /* shutdown() socket */ -# ifdef SHUTDOWN_SERVER - /* FIXME: Should have a SHUTDOWN_SERVER_INPUT & - * SHUTDOWN_SERVER_OUTPUT - */ - if (current_parsed_root->method == server_method) - SHUTDOWN_SERVER (n->socket); - else -# endif - if (shutdown (n->socket, 1) < 0) - { - error (1, 0, "shutting down server socket: %s", SOCK_STRERROR (SOCK_ERRNO)); - } - - buf->output = NULL; - } - - return 0; -} - -#endif /* NO_SOCKET_TO_FD */ - -/* - * Read a line from the server. Result does not include the terminating \n. - * - * Space for the result is malloc'd and should be freed by the caller. - * - * Returns number of bytes read. - */ -static int -read_line (resultp) - char **resultp; -{ - int status; - char *result; - int len; - - status = buf_flush (to_server, 1); - if (status != 0) - error (1, status, "writing to server"); - - status = buf_read_line (from_server, &result, &len); - if (status != 0) - { - if (status == -1) - error (1, 0, "end of file from server (consult above messages if any)"); - else if (status == -2) - error (1, 0, "out of memory"); - else - error (1, status, "reading from server"); - } - - if (resultp != NULL) - *resultp = result; - else - free (result); - - return len; -} - -#endif /* CLIENT_SUPPORT */ - - -#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT) - -/* - * Level of compression to use when running gzip on a single file. - */ -int file_gzip_level; - -#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ - -#ifdef CLIENT_SUPPORT - -/* - * The Repository for the top level of this command (not necessarily - * the CVSROOT, just the current directory at the time we do it). - */ -static char *toplevel_repos = NULL; - -/* Working directory when we first started. Note: we could speed things - up on some systems by using savecwd.h here instead of just always - storing a name. */ -char *toplevel_wd; - -static void -handle_ok (args, len) - char *args; - int len; -{ - return; -} - -static void -handle_error (args, len) - char *args; - int len; -{ - int something_printed; - - /* - * First there is a symbolic error code followed by a space, which - * we ignore. - */ - char *p = strchr (args, ' '); - if (p == NULL) - { - error (0, 0, "invalid data from cvs server"); - return; - } - ++p; - - /* Next we print the text of the message from the server. We - probably should be prefixing it with "server error" or some - such, because if it is something like "Out of memory", the - current behavior doesn't say which machine is out of - memory. */ - - len -= p - args; - something_printed = 0; - for (; len > 0; --len) - { - something_printed = 1; - putc (*p++, stderr); - } - if (something_printed) - putc ('\n', stderr); -} - -static void -handle_valid_requests (args, len) - char *args; - int len; -{ - char *p = args; - char *q; - struct request *rq; - do - { - q = strchr (p, ' '); - if (q != NULL) - *q++ = '\0'; - for (rq = requests; rq->name != NULL; ++rq) - { - if (strcmp (rq->name, p) == 0) - break; - } - if (rq->name == NULL) - /* - * It is a request we have never heard of (and thus never - * will want to use). So don't worry about it. - */ - ; - else - { - if (rq->flags & RQ_ENABLEME) - { - /* - * Server wants to know if we have this, to enable the - * feature. - */ - send_to_server (rq->name, 0); - send_to_server ("\012", 0); - } - else - rq->flags |= RQ_SUPPORTED; - } - p = q; - } while (q != NULL); - for (rq = requests; rq->name != NULL; ++rq) - { - if ((rq->flags & RQ_SUPPORTED) - || (rq->flags & RQ_ENABLEME)) - continue; - if (rq->flags & RQ_ESSENTIAL) - error (1, 0, "request `%s' not supported by server", rq->name); - } -} - - - -/* - * This is a proc for walklist(). It inverts the error return premise of - * walklist. - * - * RETURNS - * True If this path is prefixed by one of the paths in walklist and - * does not step above the prefix path. - * False Otherwise. - */ -static -int path_list_prefixed (p, closure) - Node *p; - void *closure; -{ - const char *questionable = closure; - const char *prefix = p->key; - if (strncmp (prefix, questionable, strlen (prefix))) return 0; - questionable += strlen (prefix); - while (ISDIRSEP (*questionable)) questionable++; - if (*questionable == '\0') return 1; - return pathname_levels (questionable); -} - - - -/* - * Need to validate the client pathname. Disallowed paths include: - * - * 1. Absolute paths. - * 2. Pathnames that do not reference a specifically requested update - * directory. - * - * In case 2, we actually only check that the directory is under the uppermost - * directories mentioned on the command line. - * - * RETURNS - * True If the path is valid. - * False Otherwise. - */ -static -int is_valid_client_path (pathname) - const char *pathname; -{ - /* 1. Absolute paths. */ - if (isabsolute (pathname)) return 0; - /* 2. No up-references in path. */ - if (pathname_levels (pathname) == 0) return 1; - /* 2. No Max-dotdot paths registered. */ - if (uppaths == NULL) return 0; - - return walklist (uppaths, path_list_prefixed, (void *)pathname); -} - - - -/* - * Do all the processing for PATHNAME, where pathname consists of the - * repository and the filename. The parameters we pass to FUNC are: - * DATA is just the DATA parameter which was passed to - * call_in_directory; ENT_LIST is a pointer to an entries list (which - * we manage the storage for); SHORT_PATHNAME is the pathname of the - * file relative to the (overall) directory in which the command is - * taking place; and FILENAME is the filename portion only of - * SHORT_PATHNAME. When we call FUNC, the curent directory points to - * the directory portion of SHORT_PATHNAME. */ - -static void -call_in_directory (pathname, func, data) - char *pathname; - void (*func) PROTO((char *data, List *ent_list, char *short_pathname, - char *filename)); - char *data; -{ - /* This variable holds the result of Entries_Open. */ - List *last_entries = NULL; - char *dir_name; - char *filename; - /* This is what we get when we hook up the directory (working directory - name) from PATHNAME with the filename from REPOSNAME. For example: - pathname: ccvs/src/ - reposname: /u/src/master/ccvs/foo/ChangeLog - short_pathname: ccvs/src/ChangeLog - */ - char *short_pathname; - char *p; - - /* - * Do the whole descent in parallel for the repositories, so we - * know what to put in CVS/Repository files. I'm not sure the - * full hair is necessary since the server does a similar - * computation; I suspect that we only end up creating one - * directory at a time anyway. - * - * Also note that we must *only* worry about this stuff when we - * are creating directories; `cvs co foo/bar; cd foo/bar; cvs co - * CVSROOT; cvs update' is legitimate, but in this case - * foo/bar/CVSROOT/CVS/Repository is not a subdirectory of - * foo/bar/CVS/Repository. - */ - char *reposname; - char *short_repos; - char *reposdirname; - char *rdirp; - int reposdirname_absolute; - int newdir = 0; - - assert (pathname); - - reposname = NULL; - read_line (&reposname); - assert (reposname != NULL); - - reposdirname_absolute = 0; - if (strncmp (reposname, toplevel_repos, strlen (toplevel_repos)) != 0) - { - reposdirname_absolute = 1; - short_repos = reposname; - } - else - { - short_repos = reposname + strlen (toplevel_repos) + 1; - if (short_repos[-1] != '/') - { - reposdirname_absolute = 1; - short_repos = reposname; - } - } - - /* Now that we have SHORT_REPOS, we can calculate the path to the file we - * are being requested to operate on. - */ - filename = strrchr (short_repos, '/'); - if (filename == NULL) - filename = short_repos; - else - ++filename; - - short_pathname = xmalloc (strlen (pathname) + strlen (filename) + 5); - strcpy (short_pathname, pathname); - strcat (short_pathname, filename); - - /* Now that we know the path to the file we were requested to operate on, - * we can verify that it is valid. - * - * For security reasons, if SHORT_PATHNAME is absolute or attempts to - * ascend outside of the current sanbbox, we abort. The server should not - * send us anything but relative paths which remain inside the sandbox - * here. Anything less means a trojan CVS server could create and edit - * arbitrary files on the client. - */ - if (!is_valid_client_path (short_pathname)) - { - error (0, 0, - "Server attempted to update a file via an invalid pathname:"); - error (1, 0, "`%s'.", short_pathname); - } - - reposdirname = xstrdup (short_repos); - p = strrchr (reposdirname, '/'); - if (p == NULL) - { - reposdirname = xrealloc (reposdirname, 2); - reposdirname[0] = '.'; reposdirname[1] = '\0'; - } - else - *p = '\0'; - - dir_name = xstrdup (pathname); - p = strrchr (dir_name, '/'); - if (p == NULL) - { - dir_name = xrealloc (dir_name, 2); - dir_name[0] = '.'; dir_name[1] = '\0'; - } - else - *p = '\0'; - if (client_prune_dirs) - add_prune_candidate (dir_name); - - if (toplevel_wd == NULL) - { - toplevel_wd = xgetwd (); - if (toplevel_wd == NULL) - error (1, errno, "could not get working directory"); - } - - if (CVS_CHDIR (toplevel_wd) < 0) - error (1, errno, "could not chdir to %s", toplevel_wd); - - if (CVS_CHDIR (dir_name) < 0) - { - char *dir; - char *dirp; - - if (! existence_error (errno)) - error (1, errno, "could not chdir to %s", dir_name); - - /* Directory does not exist, we need to create it. */ - newdir = 1; - - /* Provided we are willing to assume that directories get - created one at a time, we could simplify this a lot. - Do note that one aspect still would need to walk the - dir_name path: the checking for "fncmp (dir, CVSADM)". */ - - dir = xmalloc (strlen (dir_name) + 1); - dirp = dir_name; - rdirp = reposdirname; - - /* This algorithm makes nested directories one at a time - and create CVS administration files in them. For - example, we're checking out foo/bar/baz from the - repository: - - 1) create foo, point CVS/Repository to <root>/foo - 2) .. foo/bar .. <root>/foo/bar - 3) .. foo/bar/baz .. <root>/foo/bar/baz - - As you can see, we're just stepping along DIR_NAME (with - DIRP) and REPOSDIRNAME (with RDIRP) respectively. - - We need to be careful when we are checking out a - module, however, since DIR_NAME and REPOSDIRNAME are not - going to be the same. Since modules will not have any - slashes in their names, we should watch the output of - STRCHR to decide whether or not we should use STRCHR on - the RDIRP. That is, if we're down to a module name, - don't keep picking apart the repository directory name. */ - - do - { - dirp = strchr (dirp, '/'); - if (dirp) - { - strncpy (dir, dir_name, dirp - dir_name); - dir[dirp - dir_name] = '\0'; - /* Skip the slash. */ - ++dirp; - if (rdirp == NULL) - /* This just means that the repository string has - fewer components than the dir_name string. But - that is OK (e.g. see modules3-8 in testsuite). */ - ; - else - rdirp = strchr (rdirp, '/'); - } - else - { - /* If there are no more slashes in the dir name, - we're down to the most nested directory -OR- to - the name of a module. In the first case, we - should be down to a DIRP that has no slashes, - so it won't help/hurt to do another STRCHR call - on DIRP. It will definitely hurt, however, if - we're down to a module name, since a module - name can point to a nested directory (that is, - DIRP will still have slashes in it. Therefore, - we should set it to NULL so the routine below - copies the contents of REMOTEDIRNAME onto the - root repository directory (does this if rdirp - is set to NULL, because we used to do an extra - STRCHR call here). */ - - rdirp = NULL; - strcpy (dir, dir_name); - } - - if (fncmp (dir, CVSADM) == 0) - { - error (0, 0, "cannot create a directory named %s", dir); - error (0, 0, "because CVS uses \"%s\" for its own uses", - CVSADM); - error (1, 0, "rename the directory and try again"); - } - - if (mkdir_if_needed (dir)) - { - /* It already existed, fine. Just keep going. */ - } - else if (strcmp (cvs_cmd_name, "export") == 0) - /* Don't create CVSADM directories if this is export. */ - ; - else - { - /* - * Put repository in CVS/Repository. For historical - * (pre-CVS/Root) reasons, this is an absolute pathname, - * but what really matters is the part of it which is - * relative to cvsroot. - */ - char *repo; - char *r, *b; - - repo = xmalloc (strlen (reposdirname) - + strlen (toplevel_repos) - + 80); - if (reposdirname_absolute) - r = repo; - else - { - strcpy (repo, toplevel_repos); - strcat (repo, "/"); - r = repo + strlen (repo); - } - - if (rdirp) - { - /* See comment near start of function; the only - way that the server can put the right thing - in each CVS/Repository file is to create the - directories one at a time. I think that the - CVS server has been doing this all along. */ - error (0, 0, "\ -warning: server is not creating directories one at a time"); - strncpy (r, reposdirname, rdirp - reposdirname); - r[rdirp - reposdirname] = '\0'; - } - else - strcpy (r, reposdirname); - - Create_Admin (dir, dir, repo, - (char *)NULL, (char *)NULL, 0, 0, 1); - free (repo); - - b = strrchr (dir, '/'); - if (b == NULL) - Subdir_Register ((List *) NULL, (char *) NULL, dir); - else - { - *b = '\0'; - Subdir_Register ((List *) NULL, dir, b + 1); - *b = '/'; - } - } - - if (rdirp != NULL) - { - /* Skip the slash. */ - ++rdirp; - } - - } while (dirp != NULL); - free (dir); - /* Now it better work. */ - if ( CVS_CHDIR (dir_name) < 0) - error (1, errno, "could not chdir to %s", dir_name); - } - else if (strcmp (cvs_cmd_name, "export") == 0) - /* Don't create CVSADM directories if this is export. */ - ; - else if (!isdir (CVSADM)) - { - /* - * Put repository in CVS/Repository. For historical - * (pre-CVS/Root) reasons, this is an absolute pathname, - * but what really matters is the part of it which is - * relative to cvsroot. - */ - char *repo; - - if (reposdirname_absolute) - repo = reposdirname; - else - { - repo = xmalloc (strlen (reposdirname) - + strlen (toplevel_repos) - + 10); - strcpy (repo, toplevel_repos); - strcat (repo, "/"); - strcat (repo, reposdirname); - } - - Create_Admin (".", ".", repo, (char *)NULL, (char *)NULL, 0, 1, 1); - if (repo != reposdirname) - free (repo); - } - - if (strcmp (cvs_cmd_name, "export") != 0) - { - last_entries = Entries_Open (0, dir_name); - - /* If this is a newly created directory, we will record - all subdirectory information, so call Subdirs_Known in - case there are no subdirectories. If this is not a - newly created directory, it may be an old working - directory from before we recorded subdirectory - information in the Entries file. We force a search for - all subdirectories now, to make sure our subdirectory - information is up to date. If the Entries file does - record subdirectory information, then this call only - does list manipulation. */ - if (newdir) - Subdirs_Known (last_entries); - else - { - List *dirlist; - - dirlist = Find_Directories ((char *) NULL, W_LOCAL, - last_entries); - dellist (&dirlist); - } - } - free (reposdirname); - (*func) (data, last_entries, short_pathname, filename); - if (last_entries != NULL) - Entries_Close (last_entries); - free (dir_name); - free (short_pathname); - free (reposname); -} - -static void -copy_a_file (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - char *newname; -#ifdef USE_VMS_FILENAMES - char *p; -#endif - - read_line (&newname); - -#ifdef USE_VMS_FILENAMES - /* Mogrify the filename so VMS is happy with it. */ - for(p = newname; *p; p++) - if(*p == '.' || *p == '#') *p = '_'; -#endif - /* cvsclient.texi has said for a long time that newname must be in the - same directory. Wouldn't want a malicious or buggy server overwriting - ~/.profile, /etc/passwd, or anything like that. */ - if (last_component (newname) != newname) - error (1, 0, "protocol error: Copy-file tried to specify directory"); - - if (unlink_file (newname) && !existence_error (errno)) - error (0, errno, "unable to remove %s", newname); - copy_file (filename, newname); - free (newname); -} - -static void -handle_copy_file (args, len) - char *args; - int len; -{ - call_in_directory (args, copy_a_file, (char *)NULL); -} - - - -/* Attempt to read a file size from a string. Accepts base 8 (0N), base 16 - * (0xN), or base 10. Exits on error. - * - * RETURNS - * The file size, in a size_t. - * - * FATAL ERRORS - * 1. As strtoul(). - * 2. If the number read exceeds SIZE_MAX. - */ -static size_t -strto_file_size (const char *s) -{ - unsigned long tmp; - char *endptr; - - /* Read it. */ - errno = 0; - tmp = strtoul (s, &endptr, 0); - - /* Check for errors. */ - if (errno || endptr == s) - error (1, errno, "Server sent invalid file size `%s'", s); - if (*endptr != '\0') - error (1, 0, - "Server sent trailing characters in file size `%s'", - endptr); - if (tmp > SIZE_MAX) - error (1, 0, "Server sent file size exceeding client max."); - - /* Return it. */ - return (size_t)tmp; -} - - - -static void read_counted_file PROTO ((char *, char *)); - -/* Read from the server the count for the length of a file, then read - the contents of that file and write them to FILENAME. FULLNAME is - the name of the file for use in error messages. FIXME-someday: - extend this to deal with compressed files and make update_entries - use it. On error, gives a fatal error. */ -static void -read_counted_file (filename, fullname) - char *filename; - char *fullname; -{ - char *size_string; - size_t size; - char *buf; - - /* Pointers in buf to the place to put data which will be read, - and the data which needs to be written, respectively. */ - char *pread; - char *pwrite; - /* Number of bytes left to read and number of bytes in buf waiting to - be written, respectively. */ - size_t nread; - size_t nwrite; - - FILE *fp; - - read_line (&size_string); - if (size_string[0] == 'z') - error (1, 0, "\ -protocol error: compressed files not supported for that operation"); - size = strto_file_size (size_string); - free (size_string); - - /* A more sophisticated implementation would use only a limited amount - of buffer space (8K perhaps), and read that much at a time. We allocate - a buffer for the whole file only to make it easy to keep track what - needs to be read and written. */ - buf = xmalloc (size); - - /* FIXME-someday: caller should pass in a flag saying whether it - is binary or not. I haven't carefully looked into whether - CVS/Template files should use local text file conventions or - not. */ - fp = CVS_FOPEN (filename, "wb"); - if (fp == NULL) - error (1, errno, "cannot write %s", fullname); - nread = size; - nwrite = 0; - pread = buf; - pwrite = buf; - while (nread > 0 || nwrite > 0) - { - size_t n; - - if (nread > 0) - { - n = try_read_from_server (pread, nread); - nread -= n; - pread += n; - nwrite += n; - } - - if (nwrite > 0) - { - n = fwrite (pwrite, 1, nwrite, fp); - if (ferror (fp)) - error (1, errno, "cannot write %s", fullname); - nwrite -= n; - pwrite += n; - } - } - free (buf); - if (fclose (fp) < 0) - error (1, errno, "cannot close %s", fullname); -} - -/* OK, we want to swallow the "U foo.c" response and then output it only - if we can update the file. In the future we probably want some more - systematic approach to parsing tagged text, but for now we keep it - ad hoc. "Why," I hear you cry, "do we not just look at the - Update-existing and Created responses?" That is an excellent question, - and the answer is roughly conservatism/laziness--I haven't read through - update.c enough to figure out the exact correspondence or lack thereof - between those responses and a "U foo.c" line (note that Merged, from - join_file, can be either "C foo" or "U foo" depending on the context). */ -/* Nonzero if we have seen +updated and not -updated. */ -static int updated_seen; -/* Filename from an "fname" tagged response within +updated/-updated. */ -static char *updated_fname; - -/* This struct is used to hold data when reading the +importmergecmd - and -importmergecmd tags. We put the variables in a struct only - for namespace issues. FIXME: As noted above, we need to develop a - more systematic approach. */ -static struct -{ - /* Nonzero if we have seen +importmergecmd and not -importmergecmd. */ - int seen; - /* Number of conflicts, from a "conflicts" tagged response. */ - int conflicts; - /* First merge tag, from a "mergetag1" tagged response. */ - char *mergetag1; - /* Second merge tag, from a "mergetag2" tagged response. */ - char *mergetag2; - /* Repository, from a "repository" tagged response. */ - char *repository; -} importmergecmd; - -/* Nonzero if we should arrange to return with a failure exit status. */ -static int failure_exit; - - -/* - * The time stamp of the last file we registered. - */ -static time_t last_register_time; - -/* - * The Checksum response gives the checksum for the file transferred - * over by the next Updated, Merged or Patch response. We just store - * it here, and then check it in update_entries. - */ - -static int stored_checksum_valid; -static unsigned char stored_checksum[16]; - -static void -handle_checksum (args, len) - char *args; - int len; -{ - char *s; - char buf[3]; - int i; - - if (stored_checksum_valid) - error (1, 0, "Checksum received before last one was used"); - - s = args; - buf[2] = '\0'; - for (i = 0; i < 16; i++) - { - char *bufend; - - buf[0] = *s++; - buf[1] = *s++; - stored_checksum[i] = (char) strtol (buf, &bufend, 16); - if (bufend != buf + 2) - break; - } - - if (i < 16 || *s != '\0') - error (1, 0, "Invalid Checksum response: `%s'", args); - - stored_checksum_valid = 1; -} - -/* Mode that we got in a "Mode" response (malloc'd), or NULL if none. */ -static char *stored_mode; - -static void handle_mode PROTO ((char *, int)); - -static void -handle_mode (args, len) - char *args; - int len; -{ - if (stored_mode != NULL) - error (1, 0, "protocol error: duplicate Mode"); - stored_mode = xstrdup (args); -} - -/* Nonzero if time was specified in Mod-time. */ -static int stored_modtime_valid; -/* Time specified in Mod-time. */ -static time_t stored_modtime; - -static void handle_mod_time PROTO ((char *, int)); - -static void -handle_mod_time (args, len) - char *args; - int len; -{ - if (stored_modtime_valid) - error (0, 0, "protocol error: duplicate Mod-time"); - stored_modtime = get_date (args, NULL); - if (stored_modtime == (time_t) -1) - error (0, 0, "protocol error: cannot parse date %s", args); - else - stored_modtime_valid = 1; -} - -/* - * If we receive a patch, but the patch program fails to apply it, we - * want to request the original file. We keep a list of files whose - * patches have failed. - */ - -char **failed_patches; -int failed_patches_count; - -struct update_entries_data -{ - enum { - /* - * We are just getting an Entries line; the local file is - * correct. - */ - UPDATE_ENTRIES_CHECKIN, - /* We are getting the file contents as well. */ - UPDATE_ENTRIES_UPDATE, - /* - * We are getting a patch against the existing local file, not - * an entire new file. - */ - UPDATE_ENTRIES_PATCH, - /* - * We are getting an RCS change text (diff -n output) against - * the existing local file, not an entire new file. - */ - UPDATE_ENTRIES_RCS_DIFF - } contents; - - enum { - /* We are replacing an existing file. */ - UPDATE_ENTRIES_EXISTING, - /* We are creating a new file. */ - UPDATE_ENTRIES_NEW, - /* We don't know whether it is existing or new. */ - UPDATE_ENTRIES_EXISTING_OR_NEW - } existp; - - /* - * String to put in the timestamp field or NULL to use the timestamp - * of the file. - */ - char *timestamp; -}; - -/* Update the Entries line for this file. */ -static void -update_entries (data_arg, ent_list, short_pathname, filename) - char *data_arg; - List *ent_list; - char *short_pathname; - char *filename; -{ - char *entries_line; - struct update_entries_data *data = (struct update_entries_data *)data_arg; - - char *cp; - char *user; - char *vn; - /* Timestamp field. Always empty according to the protocol. */ - char *ts; - char *options = NULL; - char *tag = NULL; - char *date = NULL; - char *tag_or_date; - char *scratch_entries = NULL; - int bin; - -#ifdef UTIME_EXPECTS_WRITABLE - int change_it_back = 0; -#endif - - read_line (&entries_line); - - /* - * Parse the entries line. - */ - scratch_entries = xstrdup (entries_line); - - if (scratch_entries[0] != '/') - error (1, 0, "bad entries line `%s' from server", entries_line); - user = scratch_entries + 1; - if ((cp = strchr (user, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - vn = cp; - if ((cp = strchr (vn, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - - ts = cp; - if ((cp = strchr (ts, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - options = cp; - if ((cp = strchr (options, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - tag_or_date = cp; - - /* If a slash ends the tag_or_date, ignore everything after it. */ - cp = strchr (tag_or_date, '/'); - if (cp != NULL) - *cp = '\0'; - if (*tag_or_date == 'T') - tag = tag_or_date + 1; - else if (*tag_or_date == 'D') - date = tag_or_date + 1; - - /* Done parsing the entries line. */ - - if (data->contents == UPDATE_ENTRIES_UPDATE - || data->contents == UPDATE_ENTRIES_PATCH - || data->contents == UPDATE_ENTRIES_RCS_DIFF) - { - char *size_string; - char *mode_string; - size_t size; - char *buf; - char *temp_filename; - int use_gzip; - int patch_failed; - char *s; - - read_line (&mode_string); - - read_line (&size_string); - if (size_string[0] == 'z') - { - use_gzip = 1; - s = size_string + 1; - } - else - { - use_gzip = 0; - s = size_string; - } - size = strto_file_size (s); - free (size_string); - - /* Note that checking this separately from writing the file is - a race condition: if the existence or lack thereof of the - file changes between now and the actual calls which - operate on it, we lose. However (a) there are so many - cases, I'm reluctant to try to fix them all, (b) in some - cases the system might not even have a system call which - does the right thing, and (c) it isn't clear this needs to - work. */ - if (data->existp == UPDATE_ENTRIES_EXISTING - && !isfile (filename)) - /* Emit a warning and update the file anyway. */ - error (0, 0, "warning: %s unexpectedly disappeared", - short_pathname); - - if (data->existp == UPDATE_ENTRIES_NEW - && isfile (filename)) - { - /* Emit a warning and refuse to update the file; we don't want - to clobber a user's file. */ - size_t nread; - size_t toread; - - /* size should be unsigned, but until we get around to fixing - that, work around it. */ - size_t usize; - - char buf[8192]; - - /* This error might be confusing; it isn't really clear to - the user what to do about it. Keep in mind that it has - several causes: (1) something/someone creates the file - during the time that CVS is running, (2) the repository - has two files whose names clash for the client because - of case-insensitivity or similar causes, See 3 for - additional notes. (3) a special case of this is that a - file gets renamed for example from a.c to A.C. A - "cvs update" on a case-insensitive client will get this - error. In this case and in case 2, the filename - (short_pathname) printed in the error message will likely _not_ - have the same case as seen by the user in a directory listing. - (4) the client has a file which the server doesn't know - about (e.g. "? foo" file), and that name clashes with a file - the server does know about, (5) classify.c will print the same - message for other reasons. - - I hope the above paragraph makes it clear that making this - clearer is not a one-line fix. */ - error (0, 0, "move away %s; it is in the way", short_pathname); - if (updated_fname != NULL) - { - cvs_output ("C ", 0); - cvs_output (updated_fname, 0); - cvs_output ("\n", 1); - } - failure_exit = 1; - - discard_file_and_return: - /* Now read and discard the file contents. */ - usize = size; - nread = 0; - while (nread < usize) - { - toread = usize - nread; - if (toread > sizeof buf) - toread = sizeof buf; - - nread += try_read_from_server (buf, toread); - if (nread == usize) - break; - } - - free (mode_string); - free (scratch_entries); - free (entries_line); - - /* The Mode, Mod-time, and Checksum responses should not carry - over to a subsequent Created (or whatever) response, even - in the error case. */ - if (stored_mode != NULL) - { - free (stored_mode); - stored_mode = NULL; - } - stored_modtime_valid = 0; - stored_checksum_valid = 0; - - if (updated_fname != NULL) - { - free (updated_fname); - updated_fname = NULL; - } - return; - } - - temp_filename = xmalloc (strlen (filename) + 80); -#ifdef USE_VMS_FILENAMES - /* A VMS rename of "blah.dat" to "foo" to implies a - destination of "foo.dat" which is unfortinate for CVS */ - sprintf (temp_filename, "%s_new_", filename); -#else -#ifdef _POSIX_NO_TRUNC - sprintf (temp_filename, ".new.%.9s", filename); -#else /* _POSIX_NO_TRUNC */ - sprintf (temp_filename, ".new.%s", filename); -#endif /* _POSIX_NO_TRUNC */ -#endif /* USE_VMS_FILENAMES */ - - buf = xmalloc (size); - - /* Some systems, like OS/2 and Windows NT, end lines with CRLF - instead of just LF. Format translation is done in the C - library I/O funtions. Here we tell them whether or not to - convert -- if this file is marked "binary" with the RCS -kb - flag, then we don't want to convert, else we do (because - CVS assumes text files by default). */ - - if (options) - bin = !(strcmp (options, "-kb")); - else - bin = 0; - - if (data->contents == UPDATE_ENTRIES_RCS_DIFF) - { - /* This is an RCS change text. We just hold the change - text in memory. */ - - if (use_gzip) - error (1, 0, - "server error: gzip invalid with RCS change text"); - - read_from_server (buf, size); - } - else - { - int fd; - - fd = CVS_OPEN (temp_filename, - (O_WRONLY | O_CREAT | O_TRUNC - | (bin ? OPEN_BINARY : 0)), - 0777); - - if (fd < 0) - { - /* I can see a case for making this a fatal error; for - a condition like disk full or network unreachable - (for a file server), carrying on and giving an - error on each file seems unnecessary. But if it is - a permission problem, or some such, then it is - entirely possible that future files will not have - the same problem. */ - error (0, errno, "cannot write %s", short_pathname); - free (temp_filename); - free (buf); - goto discard_file_and_return; - } - - if (size > 0) - { - read_from_server (buf, size); - - if (use_gzip) - { - 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) - error (1, errno, "writing %s", short_pathname); - } - - if (close (fd) < 0) - error (1, errno, "writing %s", short_pathname); - } - - /* This is after we have read the file from the net (a change - from previous versions, where the server would send us - "M U foo.c" before Update-existing or whatever), but before - we finish writing the file (arguably a bug). The timing - affects a user who wants status info about how far we have - gotten, and also affects whether "U foo.c" appears in addition - to various error messages. */ - if (updated_fname != NULL) - { - cvs_output ("U ", 0); - cvs_output (updated_fname, 0); - cvs_output ("\n", 1); - free (updated_fname); - updated_fname = 0; - } - - patch_failed = 0; - - if (data->contents == UPDATE_ENTRIES_UPDATE) - { - rename_file (temp_filename, filename); - } - else if (data->contents == UPDATE_ENTRIES_PATCH) - { - /* You might think we could just leave Patched out of - Valid-responses and not get this response. However, if - memory serves, the CVS 1.9 server bases this on -u - (update-patches), and there is no way for us to send -u - or not based on whether the server supports "Rcs-diff". - - Fall back to transmitting entire files. */ - patch_failed = 1; - } - else - { - char *filebuf; - size_t filebufsize; - size_t nread; - char *patchedbuf; - size_t patchedlen; - - /* Handle UPDATE_ENTRIES_RCS_DIFF. */ - - if (!isfile (filename)) - error (1, 0, "patch original file %s does not exist", - short_pathname); - filebuf = NULL; - filebufsize = 0; - nread = 0; - - get_file (filename, short_pathname, bin ? FOPEN_BINARY_READ : "r", - &filebuf, &filebufsize, &nread); - /* At this point the contents of the existing file are in - FILEBUF, and the length of the contents is in NREAD. - The contents of the patch from the network are in BUF, - and the length of the patch is in SIZE. */ - - if (! rcs_change_text (short_pathname, filebuf, nread, buf, size, - &patchedbuf, &patchedlen)) - patch_failed = 1; - else - { - if (stored_checksum_valid) - { - struct cvs_MD5Context context; - unsigned char checksum[16]; - - /* We have a checksum. Check it before writing - the file out, so that we don't have to read it - back in again. */ - cvs_MD5Init (&context); - cvs_MD5Update (&context, - (unsigned char *) patchedbuf, patchedlen); - cvs_MD5Final (checksum, &context); - if (memcmp (checksum, stored_checksum, 16) != 0) - { - error (0, 0, - "checksum failure after patch to %s; will refetch", - short_pathname); - - patch_failed = 1; - } - - stored_checksum_valid = 0; - } - - if (! patch_failed) - { - FILE *e; - - e = open_file (temp_filename, - bin ? FOPEN_BINARY_WRITE : "w"); - if (fwrite (patchedbuf, 1, patchedlen, e) != patchedlen) - error (1, errno, "cannot write %s", temp_filename); - if (fclose (e) == EOF) - error (1, errno, "cannot close %s", temp_filename); - rename_file (temp_filename, filename); - } - - free (patchedbuf); - } - - free (filebuf); - } - - free (temp_filename); - - if (stored_checksum_valid && ! patch_failed) - { - FILE *e; - struct cvs_MD5Context context; - unsigned char buf[8192]; - unsigned len; - unsigned char checksum[16]; - - /* - * Compute the MD5 checksum. This will normally only be - * used when receiving a patch, so we always compute it - * here on the final file, rather than on the received - * data. - * - * Note that if the file is a text file, we should read it - * here using text mode, so its lines will be terminated the same - * way they were transmitted. - */ - e = CVS_FOPEN (filename, "r"); - if (e == NULL) - error (1, errno, "could not open %s", short_pathname); - - cvs_MD5Init (&context); - while ((len = fread (buf, 1, sizeof buf, e)) != 0) - cvs_MD5Update (&context, buf, len); - if (ferror (e)) - error (1, errno, "could not read %s", short_pathname); - cvs_MD5Final (checksum, &context); - - fclose (e); - - stored_checksum_valid = 0; - - if (memcmp (checksum, stored_checksum, 16) != 0) - { - if (data->contents != UPDATE_ENTRIES_PATCH) - error (1, 0, "checksum failure on %s", - short_pathname); - - error (0, 0, - "checksum failure after patch to %s; will refetch", - short_pathname); - - patch_failed = 1; - } - } - - if (patch_failed) - { - /* Save this file to retrieve later. */ - failed_patches = (char **) xrealloc ((char *) failed_patches, - ((failed_patches_count + 1) - * sizeof (char *))); - failed_patches[failed_patches_count] = xstrdup (short_pathname); - ++failed_patches_count; - - stored_checksum_valid = 0; - - free (mode_string); - free (buf); - free (scratch_entries); - free (entries_line); - - return; - } - - { - int status = change_mode (filename, mode_string, 1); - if (status != 0) - error (0, status, "cannot change mode of %s", short_pathname); - } - - free (mode_string); - free (buf); - } - - if (stored_mode != NULL) - { - change_mode (filename, stored_mode, 1); - free (stored_mode); - stored_mode = NULL; - } - - if (stored_modtime_valid) - { - struct utimbuf t; - - memset (&t, 0, sizeof (t)); - t.modtime = stored_modtime; - (void) time (&t.actime); - -#ifdef UTIME_EXPECTS_WRITABLE - if (!iswritable (filename)) - { - xchmod (filename, 1); - change_it_back = 1; - } -#endif /* UTIME_EXPECTS_WRITABLE */ - - if (utime (filename, &t) < 0) - error (0, errno, "cannot set time on %s", filename); - -#ifdef UTIME_EXPECTS_WRITABLE - if (change_it_back) - { - xchmod (filename, 0); - change_it_back = 0; - } -#endif /* UTIME_EXPECTS_WRITABLE */ - - stored_modtime_valid = 0; - } - - /* - * Process the entries line. Do this after we've written the file, - * since we need the timestamp. - */ - if (strcmp (cvs_cmd_name, "export") != 0) - { - char *local_timestamp; - char *file_timestamp; - - (void) time (&last_register_time); - - local_timestamp = data->timestamp; - if (local_timestamp == NULL || ts[0] == '+') - file_timestamp = time_stamp (filename); - else - file_timestamp = NULL; - - /* - * These special version numbers signify that it is not up to - * date. Create a dummy timestamp which will never compare - * equal to the timestamp of the file. - */ - if (vn[0] == '\0' || strcmp (vn, "0") == 0 || vn[0] == '-') - local_timestamp = "dummy timestamp"; - else if (local_timestamp == NULL) - { - local_timestamp = file_timestamp; - - /* Checking for cvs_cmd_name of "commit" doesn't seem like - the cleanest way to handle this, but it seem to roughly - parallel what the :local: code which calls - mark_up_to_date ends up amounting to. Some day, should - think more about what the Checked-in response means - vis-a-vis both Entries and Base and clarify - cvsclient.texi accordingly. */ - - if (!strcmp (cvs_cmd_name, "commit")) - mark_up_to_date (filename); - } - - Register (ent_list, filename, vn, local_timestamp, - options, tag, date, ts[0] == '+' ? file_timestamp : NULL); - - if (file_timestamp) - free (file_timestamp); - - } - free (scratch_entries); - free (entries_line); -} - -static void -handle_checked_in (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_CHECKIN; - dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; - dat.timestamp = NULL; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void -handle_new_entry (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_CHECKIN; - dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; - dat.timestamp = "dummy timestamp from new-entry"; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void -handle_updated (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_UPDATE; - dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; - dat.timestamp = NULL; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void handle_created PROTO((char *, int)); - -static void -handle_created (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_UPDATE; - dat.existp = UPDATE_ENTRIES_NEW; - dat.timestamp = NULL; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void handle_update_existing PROTO((char *, int)); - -static void -handle_update_existing (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_UPDATE; - dat.existp = UPDATE_ENTRIES_EXISTING; - dat.timestamp = NULL; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void -handle_merged (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_UPDATE; - /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case... */ - dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; - dat.timestamp = "Result of merge"; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void -handle_patched (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_PATCH; - /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case... */ - dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; - dat.timestamp = NULL; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void -handle_rcs_diff (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_RCS_DIFF; - /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case... */ - dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW; - dat.timestamp = NULL; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void -remove_entry (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - Scratch_Entry (ent_list, filename); -} - -static void -handle_remove_entry (args, len) - char *args; - int len; -{ - call_in_directory (args, remove_entry, (char *)NULL); -} - -static void -remove_entry_and_file (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - Scratch_Entry (ent_list, filename); - /* Note that we don't ignore existence_error's here. The server - should be sending Remove-entry rather than Removed in cases - where the file does not exist. And if the user removes the - file halfway through a cvs command, we should be printing an - error. */ - if (unlink_file (filename) < 0) - error (0, errno, "unable to remove %s", short_pathname); -} - -static void -handle_removed (args, len) - char *args; - int len; -{ - call_in_directory (args, remove_entry_and_file, (char *)NULL); -} - -/* Is this the top level (directory containing CVSROOT)? */ -static int -is_cvsroot_level (pathname) - char *pathname; -{ - if (strcmp (toplevel_repos, current_parsed_root->directory) != 0) - return 0; - - return strchr (pathname, '/') == NULL; -} - -static void -set_static (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - FILE *fp; - fp = open_file (CVSADM_ENTSTAT, "w+"); - if (fclose (fp) == EOF) - error (1, errno, "cannot close %s", CVSADM_ENTSTAT); -} - -static void -handle_set_static_directory (args, len) - char *args; - int len; -{ - if (strcmp (cvs_cmd_name, "export") == 0) - { - /* Swallow the repository. */ - read_line (NULL); - return; - } - call_in_directory (args, set_static, (char *)NULL); -} - -static void -clear_static (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno)) - error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); -} - -static void -handle_clear_static_directory (pathname, len) - char *pathname; - int len; -{ - if (strcmp (cvs_cmd_name, "export") == 0) - { - /* Swallow the repository. */ - read_line (NULL); - return; - } - - if (is_cvsroot_level (pathname)) - { - /* - * Top level (directory containing CVSROOT). This seems to normally - * lack a CVS directory, so don't try to create files in it. - */ - return; - } - call_in_directory (pathname, clear_static, (char *)NULL); -} - -static void -set_sticky (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - char *tagspec; - FILE *f; - - read_line (&tagspec); - - /* FIXME-update-dir: error messages should include the directory. */ - f = CVS_FOPEN (CVSADM_TAG, "w+"); - if (f == NULL) - { - /* Making this non-fatal is a bit of a kludge (see dirs2 - in testsuite). A better solution would be to avoid having - the server tell us about a directory we shouldn't be doing - anything with anyway (e.g. by handling directory - addition/removal better). */ - error (0, errno, "cannot open %s", CVSADM_TAG); - free (tagspec); - return; - } - if (fprintf (f, "%s\n", tagspec) < 0) - error (1, errno, "writing %s", CVSADM_TAG); - if (fclose (f) == EOF) - error (1, errno, "closing %s", CVSADM_TAG); - free (tagspec); -} - -static void -handle_set_sticky (pathname, len) - char *pathname; - int len; -{ - if (strcmp (cvs_cmd_name, "export") == 0) - { - /* Swallow the repository. */ - read_line (NULL); - /* Swallow the tag line. */ - read_line (NULL); - return; - } - if (is_cvsroot_level (pathname)) - { - /* - * Top level (directory containing CVSROOT). This seems to normally - * lack a CVS directory, so don't try to create files in it. - */ - - /* Swallow the repository. */ - read_line (NULL); - /* Swallow the tag line. */ - read_line (NULL); - return; - } - - call_in_directory (pathname, set_sticky, (char *)NULL); -} - -static void -clear_sticky (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - if (unlink_file (CVSADM_TAG) < 0 && ! existence_error (errno)) - error (1, errno, "cannot remove %s", CVSADM_TAG); -} - -static void -handle_clear_sticky (pathname, len) - char *pathname; - int len; -{ - if (strcmp (cvs_cmd_name, "export") == 0) - { - /* Swallow the repository. */ - read_line (NULL); - return; - } - - if (is_cvsroot_level (pathname)) - { - /* - * Top level (directory containing CVSROOT). This seems to normally - * lack a CVS directory, so don't try to create files in it. - */ - return; - } - - call_in_directory (pathname, clear_sticky, (char *)NULL); -} - - -static void template PROTO ((char *, List *, char *, char *)); - -static void -template (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - char *buf = xmalloc ( strlen ( short_pathname ) - + strlen ( CVSADM_TEMPLATE ) - + 2 ); - sprintf ( buf, "%s/%s", short_pathname, CVSADM_TEMPLATE ); - read_counted_file ( CVSADM_TEMPLATE, buf ); - free ( buf ); -} - -static void handle_template PROTO ((char *, int)); - -static void -handle_template (pathname, len) - char *pathname; - int len; -{ - call_in_directory (pathname, template, NULL); -} - - - -struct save_dir { - char *dir; - struct save_dir *next; -}; - -struct save_dir *prune_candidates; - -static void -add_prune_candidate (dir) - const char *dir; -{ - struct save_dir *p; - - if ((dir[0] == '.' && dir[1] == '\0') - || (prune_candidates != NULL - && strcmp (dir, prune_candidates->dir) == 0)) - return; - p = (struct save_dir *) xmalloc (sizeof (struct save_dir)); - p->dir = xstrdup (dir); - p->next = prune_candidates; - prune_candidates = p; -} - -static void process_prune_candidates PROTO((void)); - -static void -process_prune_candidates () -{ - struct save_dir *p; - struct save_dir *q; - - if (toplevel_wd != NULL) - { - if (CVS_CHDIR (toplevel_wd) < 0) - error (1, errno, "could not chdir to %s", toplevel_wd); - } - for (p = prune_candidates; p != NULL; ) - { - if (isemptydir (p->dir, 1)) - { - char *b; - - if (unlink_file_dir (p->dir) < 0) - error (0, errno, "cannot remove %s", p->dir); - b = strrchr (p->dir, '/'); - if (b == NULL) - Subdir_Deregister ((List *) NULL, (char *) NULL, p->dir); - else - { - *b = '\0'; - Subdir_Deregister ((List *) NULL, p->dir, b + 1); - } - } - free (p->dir); - q = p->next; - free (p); - p = q; - } - prune_candidates = NULL; -} - -/* Send a Repository line. */ - -static char *last_repos; -static char *last_update_dir; - -static void send_repository PROTO((const char *, const char *, const char *)); - -static void -send_repository (dir, repos, update_dir) - const char *dir; - const char *repos; - const char *update_dir; -{ - char *adm_name; - - /* FIXME: this is probably not the best place to check; I wish I - * knew where in here's callers to really trap this bug. To - * reproduce the bug, just do this: - * - * mkdir junk - * cd junk - * cvs -d some_repos update foo - * - * Poof, CVS seg faults and dies! It's because it's trying to - * send a NULL string to the server but dies in send_to_server. - * That string was supposed to be the repository, but it doesn't - * get set because there's no CVSADM dir, and somehow it's not - * getting set from the -d argument either... ? - */ - if (repos == NULL) - { - /* Lame error. I want a real fix but can't stay up to track - this down right now. */ - error (1, 0, "no repository"); - } - - if (update_dir == NULL || update_dir[0] == '\0') - update_dir = "."; - - if (last_repos != NULL - && strcmp (repos, last_repos) == 0 - && last_update_dir != NULL - && strcmp (update_dir, last_update_dir) == 0) - /* We've already sent it. */ - return; - - if (client_prune_dirs) - add_prune_candidate (update_dir); - - /* Add a directory name to the list of those sent to the - server. */ - if (update_dir && (*update_dir != '\0') - && (strcmp (update_dir, ".") != 0) - && (findnode (dirs_sent_to_server, update_dir) == NULL)) - { - Node *n; - n = getnode (); - n->type = NT_UNKNOWN; - n->key = xstrdup (update_dir); - n->data = NULL; - - if (addnode (dirs_sent_to_server, n)) - error (1, 0, "cannot add directory %s to list", n->key); - } - - /* 80 is large enough for any of CVSADM_*. */ - adm_name = xmalloc (strlen (dir) + 80); - - send_to_server ("Directory ", 0); - { - /* Send the directory name. I know that this - sort of duplicates code elsewhere, but each - case seems slightly different... */ - char buf[1]; - const char *p = update_dir; - while (*p != '\0') - { - assert (*p != '\012'); - if (ISDIRSEP (*p)) - { - buf[0] = '/'; - send_to_server (buf, 1); - } - else - { - buf[0] = *p; - send_to_server (buf, 1); - } - ++p; - } - } - send_to_server ("\012", 1); - send_to_server (repos, 0); - send_to_server ("\012", 1); - - if (strcmp (cvs_cmd_name, "import") - && supported_request ("Static-directory")) - { - adm_name[0] = '\0'; - if (dir[0] != '\0') - { - strcat (adm_name, dir); - strcat (adm_name, "/"); - } - strcat (adm_name, CVSADM_ENTSTAT); - if (isreadable (adm_name)) - { - send_to_server ("Static-directory\012", 0); - } - } - if (strcmp (cvs_cmd_name, "import") - && supported_request ("Sticky")) - { - FILE *f; - if (dir[0] == '\0') - strcpy (adm_name, CVSADM_TAG); - else - sprintf (adm_name, "%s/%s", dir, CVSADM_TAG); - - f = CVS_FOPEN (adm_name, "r"); - if (f == NULL) - { - if (! existence_error (errno)) - error (1, errno, "reading %s", adm_name); - } - else - { - char line[80]; - char *nl = NULL; - send_to_server ("Sticky ", 0); - while (fgets (line, sizeof (line), f) != NULL) - { - send_to_server (line, 0); - nl = strchr (line, '\n'); - if (nl != NULL) - break; - } - if (nl == NULL) - send_to_server ("\012", 1); - if (fclose (f) == EOF) - error (0, errno, "closing %s", adm_name); - } - } - free (adm_name); - if (last_repos != NULL) - free (last_repos); - if (last_update_dir != NULL) - free (last_update_dir); - last_repos = xstrdup (repos); - last_update_dir = xstrdup (update_dir); -} - -/* Send a Repository line and set toplevel_repos. */ - -void -send_a_repository (dir, repository, update_dir_in) - const char *dir; - const char *repository; - const char *update_dir_in; -{ - char *update_dir; - - assert (update_dir_in); - update_dir = xstrdup (update_dir_in); - - if (toplevel_repos == NULL && repository != NULL) - { - if (update_dir[0] == '\0' - || (update_dir[0] == '.' && update_dir[1] == '\0')) - toplevel_repos = xstrdup (repository); - else - { - /* - * Get the repository from a CVS/Repository file if update_dir - * is absolute. This is not correct in general, because - * the CVS/Repository file might not be the top-level one. - * This is for cases like "cvs update /foo/bar" (I'm not - * sure it matters what toplevel_repos we get, but it does - * matter that we don't hit the "internal error" code below). - */ - if (update_dir[0] == '/') - toplevel_repos = Name_Repository (update_dir, update_dir); - else - { - /* - * Guess the repository of that directory by looking at a - * subdirectory and removing as many pathname components - * as are in update_dir. I think that will always (or at - * least almost always) be 1. - * - * So this deals with directories which have been - * renamed, though it doesn't necessarily deal with - * directories which have been put inside other - * directories (and cvs invoked on the containing - * directory). I'm not sure the latter case needs to - * work. - * - * 21 Aug 1998: Well, Mr. Above-Comment-Writer, it - * does need to work after all. When we are using the - * client in a multi-cvsroot environment, it will be - * fairly common that we have the above case (e.g., - * cwd checked out from one repository but - * subdirectory checked out from another). We can't - * assume that by walking up a directory in our wd we - * necessarily walk up a directory in the repository. - */ - /* - * This gets toplevel_repos wrong for "cvs update ../foo" - * but I'm not sure toplevel_repos matters in that case. - */ - - int repository_len, update_dir_len; - - strip_trailing_slashes (update_dir); - - repository_len = strlen (repository); - update_dir_len = strlen (update_dir); - - /* Try to remove the path components in UPDATE_DIR - from REPOSITORY. If the path elements don't exist - in REPOSITORY, or the removal of those path - elements mean that we "step above" - current_parsed_root->directory, set toplevel_repos to - current_parsed_root->directory. */ - if ((repository_len > update_dir_len) - && (strcmp (repository + repository_len - update_dir_len, - update_dir) == 0) - /* TOPLEVEL_REPOS shouldn't be above current_parsed_root->directory */ - && ((size_t)(repository_len - update_dir_len) - > strlen (current_parsed_root->directory))) - { - /* The repository name contains UPDATE_DIR. Set - toplevel_repos to the repository name without - UPDATE_DIR. */ - - toplevel_repos = xmalloc (repository_len - update_dir_len); - /* Note that we don't copy the trailing '/'. */ - strncpy (toplevel_repos, repository, - repository_len - update_dir_len - 1); - toplevel_repos[repository_len - update_dir_len - 1] = '\0'; - } - else - { - toplevel_repos = xstrdup (current_parsed_root->directory); - } - } - } - } - - send_repository (dir, repository, update_dir); - free (update_dir); -} - - - -/* The "expanded" modules. */ -static int modules_count; -static int modules_allocated; -static char **modules_vector; - -static void -handle_module_expansion (args, len) - char *args; - int len; -{ - if (modules_vector == NULL) - { - modules_allocated = 1; /* Small for testing */ - modules_vector = (char **) xmalloc - (modules_allocated * sizeof (modules_vector[0])); - } - else if (modules_count >= modules_allocated) - { - modules_allocated *= 2; - modules_vector = (char **) xrealloc - ((char *) modules_vector, - modules_allocated * sizeof (modules_vector[0])); - } - modules_vector[modules_count] = xmalloc (strlen (args) + 1); - strcpy (modules_vector[modules_count], args); - ++modules_count; -} - -/* Original, not "expanded" modules. */ -static int module_argc; -static char **module_argv; - -void -client_expand_modules (argc, argv, local) - int argc; - char **argv; - int local; -{ - int errs; - int i; - - module_argc = argc; - module_argv = (char **) xmalloc ((argc + 1) * sizeof (module_argv[0])); - for (i = 0; i < argc; ++i) - module_argv[i] = xstrdup (argv[i]); - module_argv[argc] = NULL; - - for (i = 0; i < argc; ++i) - send_arg (argv[i]); - send_a_repository ("", current_parsed_root->directory, ""); - - send_to_server ("expand-modules\012", 0); - - errs = get_server_responses (); - if (last_repos != NULL) - free (last_repos); - last_repos = NULL; - if (last_update_dir != NULL) - free (last_update_dir); - last_update_dir = NULL; - if (errs) - error (errs, 0, "cannot expand modules"); -} - -void -client_send_expansions (local, where, build_dirs) - int local; - char *where; - int build_dirs; -{ - int i; - char *argv[1]; - - /* Send the original module names. The "expanded" module name might - not be suitable as an argument to a co request (e.g. it might be - the result of a -d argument in the modules file). It might be - cleaner if we genuinely expanded module names, all the way to a - local directory and repository, but that isn't the way it works - now. */ - send_file_names (module_argc, module_argv, 0); - - for (i = 0; i < modules_count; ++i) - { - argv[0] = where ? where : modules_vector[i]; - if (isfile (argv[0])) - send_files (1, argv, local, 0, build_dirs ? SEND_BUILD_DIRS : 0); - } - send_a_repository ("", current_parsed_root->directory, ""); -} - -void -client_nonexpanded_setup () -{ - send_a_repository ("", current_parsed_root->directory, ""); -} - -/* Receive a cvswrappers line from the server; it must be a line - containing an RCS option (e.g., "*.exe -k 'b'"). - - Note that this doesn't try to handle -t/-f options (which are a - whole separate issue which noone has thought much about, as far - as I know). - - We need to know the keyword expansion mode so we know whether to - read the file in text or binary mode. */ - -static void -handle_wrapper_rcs_option (args, len) - char *args; - int len; -{ - char *p; - - /* Enforce the notes in cvsclient.texi about how the response is not - as free-form as it looks. */ - p = strchr (args, ' '); - if (p == NULL) - goto handle_error; - if (*++p != '-' - || *++p != 'k' - || *++p != ' ' - || *++p != '\'') - goto handle_error; - if (strchr (p, '\'') == NULL) - goto handle_error; - - /* Add server-side cvswrappers line to our wrapper list. */ - wrap_add (args, 0); - return; - handle_error: - error (0, errno, "protocol error: ignoring invalid wrappers %s", args); -} - - -static void -handle_m (args, len) - char *args; - int len; -{ - /* In the case where stdout and stderr point to the same place, - fflushing stderr will make output happen in the correct order. - Often stderr will be line-buffered and this won't be needed, - but not always (is that true? I think the comment is probably - based on being confused between default buffering between - stdout and stderr. But I'm not sure). */ - fflush (stderr); - fwrite (args, len, sizeof (*args), stdout); - putc ('\n', stdout); -} - -static void handle_mbinary PROTO ((char *, int)); - -static void -handle_mbinary (args, len) - char *args; - int len; -{ - char *size_string; - size_t size; - size_t totalread; - size_t nread; - size_t toread; - char buf[8192]; - - /* See comment at handle_m about (non)flush of stderr. */ - - /* Get the size. */ - read_line (&size_string); - size = strto_file_size (size_string); - free (size_string); - - /* OK, now get all the data. The algorithm here is that we read - as much as the network wants to give us in - try_read_from_server, and then we output it all, and then - repeat, until we get all the data. */ - totalread = 0; - while (totalread < size) - { - toread = size - totalread; - if (toread > sizeof buf) - toread = sizeof buf; - - nread = try_read_from_server (buf, toread); - cvs_output_binary (buf, nread); - totalread += nread; - } -} - -static void -handle_e (args, len) - char *args; - int len; -{ - /* In the case where stdout and stderr point to the same place, - fflushing stdout will make output happen in the correct order. */ - fflush (stdout); - fwrite (args, len, sizeof (*args), stderr); - putc ('\n', stderr); -} - -/*ARGSUSED*/ -static void -handle_f (args, len) - char *args; - int len; -{ - fflush (stderr); -} - -static void handle_mt PROTO ((char *, int)); - -static void -handle_mt (args, len) - char *args; - int len; -{ - char *p; - char *tag = args; - char *text; - - /* See comment at handle_m for more details. */ - fflush (stderr); - - p = strchr (args, ' '); - if (p == NULL) - text = NULL; - else - { - *p++ = '\0'; - text = p; - } - - switch (tag[0]) - { - case '+': - if (strcmp (tag, "+updated") == 0) - updated_seen = 1; - else if (strcmp (tag, "+importmergecmd") == 0) - importmergecmd.seen = 1; - break; - case '-': - if (strcmp (tag, "-updated") == 0) - updated_seen = 0; - else if (strcmp (tag, "-importmergecmd") == 0) - { - char buf[80]; - - /* Now that we have gathered the information, we can - output the suggested merge command. */ - - if (importmergecmd.conflicts == 0 - || importmergecmd.mergetag1 == NULL - || importmergecmd.mergetag2 == NULL - || importmergecmd.repository == NULL) - { - error (0, 0, - "invalid server: incomplete importmergecmd tags"); - break; - } - - sprintf (buf, "\n%d conflicts created by this import.\n", - importmergecmd.conflicts); - cvs_output (buf, 0); - cvs_output ("Use the following command to help the merge:\n\n", - 0); - cvs_output ("\t", 1); - cvs_output (program_name, 0); - if (CVSroot_cmdline != NULL) - { - cvs_output (" -d ", 0); - cvs_output (CVSroot_cmdline, 0); - } - cvs_output (" checkout -j", 0); - cvs_output (importmergecmd.mergetag1, 0); - cvs_output (" -j", 0); - cvs_output (importmergecmd.mergetag2, 0); - cvs_output (" ", 1); - cvs_output (importmergecmd.repository, 0); - cvs_output ("\n\n", 0); - - /* Clear the static variables so that everything is - ready for any subsequent importmergecmd tag. */ - importmergecmd.conflicts = 0; - free (importmergecmd.mergetag1); - importmergecmd.mergetag1 = NULL; - free (importmergecmd.mergetag2); - importmergecmd.mergetag2 = NULL; - free (importmergecmd.repository); - importmergecmd.repository = NULL; - - importmergecmd.seen = 0; - } - break; - default: - if (updated_seen) - { - if (strcmp (tag, "fname") == 0) - { - if (updated_fname != NULL) - { - /* Output the previous message now. This can happen - if there was no Update-existing or other such - response, due to the -n global option. */ - cvs_output ("U ", 0); - cvs_output (updated_fname, 0); - cvs_output ("\n", 1); - free (updated_fname); - } - updated_fname = xstrdup (text); - } - /* Swallow all other tags. Either they are extraneous - or they reflect future extensions that we can - safely ignore. */ - } - else if (importmergecmd.seen) - { - if (strcmp (tag, "conflicts") == 0) - importmergecmd.conflicts = text ? atoi (text) : -1; - else if (strcmp (tag, "mergetag1") == 0) - importmergecmd.mergetag1 = xstrdup (text); - else if (strcmp (tag, "mergetag2") == 0) - importmergecmd.mergetag2 = xstrdup (text); - else if (strcmp (tag, "repository") == 0) - importmergecmd.repository = xstrdup (text); - /* Swallow all other tags. Either they are text for - which we are going to print our own version when we - see -importmergecmd, or they are future extensions - we can safely ignore. */ - } - else if (strcmp (tag, "newline") == 0) - printf ("\n"); - else if (text != NULL) - printf ("%s", text); - } -} - -#endif /* CLIENT_SUPPORT */ -#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT) - -/* This table must be writeable if the server code is included. */ -struct response responses[] = -{ -#ifdef CLIENT_SUPPORT -#define RSP_LINE(n, f, t, s) {n, f, t, s} -#else /* ! CLIENT_SUPPORT */ -#define RSP_LINE(n, f, t, s) {n, s} -#endif /* CLIENT_SUPPORT */ - - RSP_LINE("ok", handle_ok, response_type_ok, rs_essential), - RSP_LINE("error", handle_error, response_type_error, rs_essential), - RSP_LINE("Valid-requests", handle_valid_requests, response_type_normal, - rs_essential), - RSP_LINE("Checked-in", handle_checked_in, response_type_normal, - rs_essential), - RSP_LINE("New-entry", handle_new_entry, response_type_normal, rs_optional), - RSP_LINE("Checksum", handle_checksum, response_type_normal, rs_optional), - RSP_LINE("Copy-file", handle_copy_file, response_type_normal, rs_optional), - RSP_LINE("Updated", handle_updated, response_type_normal, rs_essential), - RSP_LINE("Created", handle_created, response_type_normal, rs_optional), - RSP_LINE("Update-existing", handle_update_existing, response_type_normal, - rs_optional), - RSP_LINE("Merged", handle_merged, response_type_normal, rs_essential), - RSP_LINE("Patched", handle_patched, response_type_normal, rs_optional), - RSP_LINE("Rcs-diff", handle_rcs_diff, response_type_normal, rs_optional), - RSP_LINE("Mode", handle_mode, response_type_normal, rs_optional), - RSP_LINE("Mod-time", handle_mod_time, response_type_normal, rs_optional), - RSP_LINE("Removed", handle_removed, response_type_normal, rs_essential), - RSP_LINE("Remove-entry", handle_remove_entry, response_type_normal, - rs_optional), - RSP_LINE("Set-static-directory", handle_set_static_directory, - response_type_normal, - rs_optional), - RSP_LINE("Clear-static-directory", handle_clear_static_directory, - response_type_normal, - rs_optional), - RSP_LINE("Set-sticky", handle_set_sticky, response_type_normal, - rs_optional), - RSP_LINE("Clear-sticky", handle_clear_sticky, response_type_normal, - rs_optional), - RSP_LINE("Template", handle_template, response_type_normal, - rs_optional), - RSP_LINE("Notified", handle_notified, response_type_normal, rs_optional), - RSP_LINE("Module-expansion", handle_module_expansion, response_type_normal, - rs_optional), - RSP_LINE("Wrapper-rcsOption", handle_wrapper_rcs_option, - response_type_normal, - rs_optional), - RSP_LINE("M", handle_m, response_type_normal, rs_essential), - RSP_LINE("Mbinary", handle_mbinary, response_type_normal, rs_optional), - RSP_LINE("E", handle_e, response_type_normal, rs_essential), - RSP_LINE("F", handle_f, response_type_normal, rs_optional), - RSP_LINE("MT", handle_mt, response_type_normal, rs_optional), - /* Possibly should be response_type_error. */ - RSP_LINE(NULL, NULL, response_type_normal, rs_essential) - -#undef RSP_LINE -}; - -#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ -#ifdef CLIENT_SUPPORT - -/* - * If LEN is 0, then send_to_server() computes string's length itself. - * - * Therefore, pass the real length when transmitting data that might - * contain 0's. - */ -void -send_to_server (str, len) - const char *str; - size_t len; -{ - static int nbytes; - - if (len == 0) - len = strlen (str); - - buf_output (to_server, str, len); - - /* There is no reason not to send data to the server, so do it - whenever we've accumulated enough information in the buffer to - make it worth sending. */ - nbytes += len; - if (nbytes >= 2 * BUFFER_DATA_SIZE) - { - int status; - - status = buf_send_output (to_server); - if (status != 0) - error (1, status, "error writing to server"); - nbytes = 0; - } -} - -/* Read up to LEN bytes from the server. Returns actual number of - bytes read, which will always be at least one; blocks if there is - no data available at all. Gives a fatal error on EOF or error. */ -static size_t -try_read_from_server (buf, len) - char *buf; - size_t len; -{ - int status, nread; - char *data; - - status = buf_read_data (from_server, len, &data, &nread); - if (status != 0) - { - if (status == -1) - error (1, 0, - "end of file from server (consult above messages if any)"); - else if (status == -2) - error (1, 0, "out of memory"); - else - error (1, status, "reading from server"); - } - - memcpy (buf, data, nread); - - return nread; -} - -/* - * Read LEN bytes from the server or die trying. - */ -void -read_from_server (buf, len) - char *buf; - size_t len; -{ - size_t red = 0; - while (red < len) - { - red += try_read_from_server (buf + red, len - red); - if (red == len) - break; - } -} - -/* - * Get some server responses and process them. Returns nonzero for - * error, 0 for success. */ -int -get_server_responses () -{ - struct response *rs; - do - { - char *cmd; - int len; - - len = read_line (&cmd); - for (rs = responses; rs->name != NULL; ++rs) - if (strncmp (cmd, rs->name, strlen (rs->name)) == 0) - { - int cmdlen = strlen (rs->name); - if (cmd[cmdlen] == '\0') - ; - else if (cmd[cmdlen] == ' ') - ++cmdlen; - else - /* - * The first len characters match, but it's a different - * response. e.g. the response is "oklahoma" but we - * matched "ok". - */ - continue; - (*rs->func) (cmd + cmdlen, len - cmdlen); - break; - } - if (rs->name == NULL) - /* It's OK to print just to the first '\0'. */ - /* We might want to handle control characters and the like - in some other way other than just sending them to stdout. - One common reason for this error is if people use :ext: - with a version of rsh which is doing CRLF translation or - something, and so the client gets "ok^M" instead of "ok". - Right now that will tend to print part of this error - message over the other part of it. It seems like we could - do better (either in general, by quoting or omitting all - control characters, and/or specifically, by detecting the CRLF - case and printing a specific error message). */ - error (0, 0, - "warning: unrecognized response `%s' from cvs server", - cmd); - free (cmd); - } while (rs->type == response_type_normal); - - if (updated_fname != NULL) - { - /* Output the previous message now. This can happen - if there was no Update-existing or other such - response, due to the -n global option. */ - cvs_output ("U ", 0); - cvs_output (updated_fname, 0); - cvs_output ("\n", 1); - free (updated_fname); - updated_fname = NULL; - } - - if (rs->type == response_type_error) - return 1; - if (failure_exit) - return 1; - return 0; -} - - - -/* Get the responses and then close the connection. */ - -/* - * Flag var; we'll set it in start_server() and not one of its - * callees, such as start_rsh_server(). This means that there might - * be a small window between the starting of the server and the - * setting of this var, but all the code in that window shouldn't care - * because it's busy checking return values to see if the server got - * started successfully anyway. - */ -int server_started = 0; - -int -get_responses_and_close () -{ - int errs = get_server_responses (); - int status; - - /* The following is necessary when working with multiple cvsroots, at least - * with commit. It used to be buried nicely in do_deferred_progs() before - * that function was removed. I suspect it wouldn't be necessary if - * call_in_directory() saved its working directory via save_cwd() before - * changing its directory and restored the saved working directory via - * restore_cwd() before exiting. Of course, calling CVS_CHDIR only once, - * here, may be more efficient. - */ - if( toplevel_wd != NULL ) - { - if( CVS_CHDIR( toplevel_wd ) < 0 ) - error( 1, errno, "could not chdir to %s", toplevel_wd ); - } - - if (client_prune_dirs) - process_prune_candidates (); - - /* First we shut down TO_SERVER. That tells the server that its input is - * finished. It then shuts down the buffer it is sending to us, at which - * point our shut down of FROM_SERVER will complete. - */ - - status = buf_shutdown (to_server); - if (status != 0) - error (0, status, "shutting down buffer to server"); - buf_free (to_server); - to_server = NULL; - - status = buf_shutdown (from_server); - if (status != 0) - error (0, status, "shutting down buffer from server"); - buf_free (from_server); - from_server = NULL; - server_started = 0; - - /* see if we need to sleep before returning to avoid time-stamp races */ - if (last_register_time) - { - sleep_past (last_register_time); - } - - return errs; -} - -#ifndef NO_EXT_METHOD -static void start_rsh_server PROTO((cvsroot_t *, struct buffer **, struct buffer **)); -#endif - -int -supported_request (name) - char *name; -{ - struct request *rq; - - for (rq = requests; rq->name; rq++) - if (!strcmp (rq->name, name)) - return (rq->flags & RQ_SUPPORTED) != 0; - error (1, 0, "internal error: testing support for unknown option?"); - /* NOTREACHED */ - return 0; -} - - - -#if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI) -static struct hostent *init_sockaddr PROTO ((struct sockaddr_in *, char *, - unsigned int)); - -static struct hostent * -init_sockaddr (name, hostname, port) - struct sockaddr_in *name; - char *hostname; - unsigned int port; -{ - struct hostent *hostinfo; - unsigned short shortport = port; - - memset (name, 0, sizeof (*name)); - name->sin_family = AF_INET; - name->sin_port = htons (shortport); - hostinfo = gethostbyname (hostname); - if (hostinfo == NULL) - { - fprintf (stderr, "Unknown host %s.\n", hostname); - error_exit (); - } - name->sin_addr = *(struct in_addr *) hostinfo->h_addr; - return hostinfo; -} - - - -/* Generic function to do port number lookup tasks. - * - * In order of precedence, will return: - * getenv (envname), if defined - * getservbyname (portname), if defined - * defaultport - */ -static int -get_port_number (envname, portname, defaultport) - const char *envname; - const char *portname; - int defaultport; -{ - struct servent *s; - char *port_s; - - if (envname && (port_s = getenv (envname))) - { - int port = atoi (port_s); - if (port <= 0) - { - error (0, 0, "%s must be a positive integer! If you", envname); - error (0, 0, "are trying to force a connection via rsh, please"); - error (0, 0, "put \":server:\" at the beginning of your CVSROOT"); - error (1, 0, "variable."); - } - return port; - } - else if (portname && (s = getservbyname (portname, "tcp"))) - return ntohs (s->s_port); - else - return defaultport; -} - - - -/* get the port number for a client to connect to based on the port - * and method of a cvsroot_t. - * - * we do this here instead of in parse_cvsroot so that we can keep network - * code confined to a localized area and also to delay the lookup until the - * last possible moment so it remains possible to run cvs client commands that - * skip opening connections to the server (i.e. skip network operations - * entirely) - * - * and yes, I know none of the commands do that now, but here's to planning - * for the future, eh? cheers. - * - * FIXME - We could cache the port lookup safely right now as we never change - * it for a single root on the fly, but we'd have to un'const some other - * functions - REMOVE_FIXME? This may be unecessary. We're talking about, - * what, usually one, sometimes two lookups of the port per invocation. I - * think twice is by far the rarer of the two cases - only the login function - * will need to do it to save the canonical CVSROOT. -DRP - */ -int -get_cvs_port_number (root) - const cvsroot_t *root; -{ - - if (root->port) return root->port; - - switch (root->method) - { -# ifdef HAVE_GSSAPI - case gserver_method: -# endif /* HAVE_GSSAPI */ -# ifdef AUTH_CLIENT_SUPPORT - case pserver_method: -# endif /* AUTH_CLIENT_SUPPORT */ -# if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI) - return get_port_number ("CVS_CLIENT_PORT", "cvspserver", CVS_AUTH_PORT); -# endif /* defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI) */ -# ifdef HAVE_KERBEROS - case kserver_method: - return get_port_number ("CVS_CLIENT_PORT", "cvs", CVS_PORT); -# endif /* HAVE_KERBEROS */ - default: - error(1, EINVAL, "internal error: get_cvs_port_number called for invalid connection method (%s)", - method_names[root->method]); - break; - } - /* NOTREACHED */ - return -1; -} - - - -void -make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, is_sock) - int tofd; - int fromfd; - int child_pid; - struct buffer **to_server; - struct buffer **from_server; - int is_sock; -{ - FILE *to_server_fp; - FILE *from_server_fp; - -# ifdef NO_SOCKET_TO_FD - if (is_sock) - { - assert (tofd == fromfd); - *to_server = socket_buffer_initialize (tofd, 0, - (BUFMEMERRPROC) NULL); - *from_server = socket_buffer_initialize (tofd, 1, - (BUFMEMERRPROC) NULL); - } - else -# endif /* NO_SOCKET_TO_FD */ - { - /* todo: some OS's don't need these calls... */ - close_on_exec (tofd); - close_on_exec (fromfd); - - /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes - fdopening the same file descriptor twice, so dup it if it is the - same. */ - if (tofd == fromfd) - { - fromfd = dup (tofd); - if (fromfd < 0) - error (1, errno, "cannot dup net connection"); - } - - /* These will use binary mode on systems which have it. */ - /* - * Also, we know that from_server is shut down second, so we pass - * child_pid in there. In theory, it should be stored in both - * buffers with a ref count... - */ - to_server_fp = fdopen (tofd, FOPEN_BINARY_WRITE); - if (to_server_fp == NULL) - error (1, errno, "cannot fdopen %d for write", tofd); - *to_server = stdio_buffer_initialize (to_server_fp, 0, 0, - (BUFMEMERRPROC) NULL); - - from_server_fp = fdopen (fromfd, FOPEN_BINARY_READ); - if (from_server_fp == NULL) - error (1, errno, "cannot fdopen %d for read", fromfd); - *from_server = stdio_buffer_initialize (from_server_fp, child_pid, 1, - (BUFMEMERRPROC) NULL); - } -} -#endif /* defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_KERBEROS) || defined(HAVE_GSSAPI) */ - - - -#if defined (AUTH_CLIENT_SUPPORT) || defined(HAVE_GSSAPI) -/* Connect to the authenticating server. - - If VERIFY_ONLY is non-zero, then just verify that the password is - correct and then shutdown the connection. - - If VERIFY_ONLY is 0, then really connect to the server. - - If DO_GSSAPI is non-zero, then we use GSSAPI authentication rather - than the pserver password authentication. - - If we fail to connect or if access is denied, then die with fatal - error. */ -void -connect_to_pserver (root, to_server_p, from_server_p, verify_only, do_gssapi) - cvsroot_t *root; - struct buffer **to_server_p; - struct buffer **from_server_p; - int verify_only; - int do_gssapi; -{ - int sock; - int port_number; - struct sockaddr_in client_sai; - struct hostent *hostinfo; - struct buffer *to_server, *from_server; - - sock = socket (AF_INET, SOCK_STREAM, 0); - if (sock == -1) - { - error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO)); - } - port_number = get_cvs_port_number (root); - hostinfo = init_sockaddr (&client_sai, root->hostname, port_number); - if (trace) - { - fprintf (stderr, " -> Connecting to %s(%s):%d\n", - root->hostname, - inet_ntoa (client_sai.sin_addr), port_number); - } - if (connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai)) - < 0) - error (1, 0, "connect to %s(%s):%d failed: %s", - root->hostname, - inet_ntoa (client_sai.sin_addr), - port_number, SOCK_STRERROR (SOCK_ERRNO)); - - make_bufs_from_fds (sock, sock, 0, &to_server, &from_server, 1); - - auth_server (root, to_server, from_server, verify_only, do_gssapi, hostinfo); - - if (verify_only) - { - int status; - - status = buf_shutdown (to_server); - if (status != 0) - error (0, status, "shutting down buffer to server"); - buf_free (to_server); - to_server = NULL; - - status = buf_shutdown (from_server); - if (status != 0) - error (0, status, "shutting down buffer from server"); - buf_free (from_server); - from_server = NULL; - - /* Don't need to set server_started = 0 since we don't set it to 1 - * until returning from this call. - */ - } - else - { - *to_server_p = to_server; - *from_server_p = from_server; - } - - return; -} - - - -static void -auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi, hostinfo) - cvsroot_t *root; - struct buffer *lto_server; - struct buffer *lfrom_server; - int verify_only; - int do_gssapi; - struct hostent *hostinfo; -{ - char *username = ""; /* the username we use to connect */ - char no_passwd = 0; /* gets set if no password found */ - - /* FIXME!!!!!!!!!!!!!!!!!! - * - * THIS IS REALLY UGLY! - * - * I'm setting the globals here so we can make calls to send_to_server & - * read_line. This happens again _after_ we return if we're not in - * verify_only mode. We should be relying on the values we passed in, but - * sent_to_server and read_line don't require an outside buf yet. - */ - to_server = lto_server; - from_server = lfrom_server; - - /* Run the authorization mini-protocol before anything else. */ - if (do_gssapi) - { -# ifdef HAVE_GSSAPI - FILE *fp = stdio_buffer_get_file(lto_server); - int fd = fp ? fileno(fp) : -1; - struct stat s; - - if ((fd < 0) || (fstat (fd, &s) < 0) || !S_ISSOCK(s.st_mode)) - { - error (1, 0, "gserver currently only enabled for socket connections"); - } - - if (! connect_to_gserver (root, fd, hostinfo)) - { - error (1, 0, - "authorization failed: server %s rejected access to %s", - root->hostname, root->directory); - } -# else /* ! HAVE_GSSAPI */ - error (1, 0, "INTERNAL ERROR: This client does not support GSSAPI authentication"); -# endif /* HAVE_GSSAPI */ - } - else /* ! do_gssapi */ - { -# ifdef AUTH_CLIENT_SUPPORT - char *begin = NULL; - char *password = NULL; - char *end = NULL; - - if (verify_only) - { - begin = "BEGIN VERIFICATION REQUEST"; - end = "END VERIFICATION REQUEST"; - } - else - { - begin = "BEGIN AUTH REQUEST"; - end = "END AUTH REQUEST"; - } - - /* Get the password, probably from ~/.cvspass. */ - password = get_cvs_password (); - username = root->username ? root->username : getcaller(); - - /* 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. */ - send_to_server(begin, 0); - send_to_server("\012", 1); - - /* Send the data the server needs. */ - send_to_server(root->directory, 0); - send_to_server("\012", 1); - send_to_server(username, 0); - send_to_server("\012", 1); - send_to_server(password, 0); - send_to_server("\012", 1); - - /* Announce that we're ending the authorization protocol. */ - send_to_server(end, 0); - send_to_server("\012", 1); - - free_cvs_password (password); - password = NULL; -# else /* ! AUTH_CLIENT_SUPPORT */ - error (1, 0, "INTERNAL ERROR: This client does not support pserver authentication"); -# endif /* AUTH_CLIENT_SUPPORT */ - } /* if (do_gssapi) */ - - { - char *read_buf; - - /* Loop, getting responses from the server. */ - while (1) - { - read_line (&read_buf); - - if (strcmp (read_buf, "I HATE YOU") == 0) - { - /* Authorization not granted. - * - * This is a little confusing since we can reach this while loop in GSSAPI - * mode, but if GSSAPI authentication failed, we already jumped to the - * rejected label (there is no case where the connect_to_gserver function - * can return 1 and we will not receive "I LOVE YOU" from the server, barring - * broken connections and garbled messages, of course). - * - * i.e. This is a pserver specific error message and should be since - * GSSAPI doesn't use username. - */ - error (0, 0, - "authorization failed: server %s rejected access to %s for user %s", - root->hostname, root->directory, 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"); - } - error_exit(); - } - else if (strncmp (read_buf, "E ", 2) == 0) - { - fprintf (stderr, "%s\n", read_buf + 2); - - /* Continue with the authentication protocol. */ - } - else if (strncmp (read_buf, "error ", 6) == 0) - { - char *p; - - /* First skip the code. */ - p = read_buf + 6; - while (*p != ' ' && *p != '\0') - ++p; - - /* Skip the space that follows the code. */ - if (*p == ' ') - ++p; - - /* Now output the text. */ - fprintf (stderr, "%s\n", p); - error_exit(); - } - else if (strcmp (read_buf, "I LOVE YOU") == 0) - { - free (read_buf); - break; - } - else - { - error (1, 0, - "unrecognized auth response from %s: %s", - root->hostname, read_buf); - } - free (read_buf); - } - } -} -#endif /* defined (AUTH_CLIENT_SUPPORT) || defined(HAVE_GSSAPI) */ - - - -#ifdef CLIENT_SUPPORT -/* void - * connect_to_forked_server ( struct buffer **to_server, - * struct buffer **from_server ) - * - * Connect to a forked server process. - */ -void -connect_to_forked_server (to_server, from_server) - struct buffer **to_server; - struct buffer **from_server; -{ - int tofd, fromfd; - int child_pid; - - /* This is pretty simple. All we need to do is choose the correct - cvs binary and call piped_child. */ - - const char *command[3]; - - command[0] = getenv ("CVS_SERVER"); - if (! command[0]) - command[0] = program_path; - - command[1] = "server"; - command[2] = NULL; - - if (trace) - { - fprintf (stderr, " -> Forking server: %s %s\n", command[0], command[1]); - } - - child_pid = piped_child (command, &tofd, &fromfd, 0); - if (child_pid < 0) - error (1, 0, "could not fork server process"); - - make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, 0); -} -#endif /* CLIENT_SUPPORT */ - - - -#ifdef HAVE_KERBEROS -/* This function has not been changed to deal with NO_SOCKET_TO_FD - (i.e., systems on which sockets cannot be converted to file - descriptors). The first person to try building a kerberos client - on such a system (OS/2, Windows 95, and maybe others) will have to - take care of this. */ -void -start_tcp_server (root, to_server, from_server) - cvsroot_t *root; - struct buffer **to_server; - struct buffer **from_server; -{ - int s; - const char *portenv; - int port; - struct hostent *hp; - struct sockaddr_in sin; - char *hname; - - s = socket (AF_INET, SOCK_STREAM, 0); - if (s < 0) - error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO)); - - port = get_cvs_port_number (root); - - hp = init_sockaddr (&sin, root->hostname, port); - - hname = xstrdup (hp->h_name); - - if (trace) - { - fprintf (stderr, " -> Connecting to %s(%s):%d\n", - root->hostname, - inet_ntoa (sin.sin_addr), port); - } - - if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0) - error (1, 0, "connect to %s(%s):%d failed: %s", - root->hostname, - inet_ntoa (sin.sin_addr), - port, SOCK_STRERROR (SOCK_ERRNO)); - - { - const char *realm; - struct sockaddr_in laddr; - int laddrlen; - KTEXT_ST ticket; - MSG_DAT msg_data; - CREDENTIALS cred; - int status; - - realm = krb_realmofhost (hname); - - laddrlen = sizeof (laddr); - if (getsockname (s, (struct sockaddr *) &laddr, &laddrlen) < 0) - error (1, 0, "getsockname failed: %s", SOCK_STRERROR (SOCK_ERRNO)); - - /* We don't care about the checksum, and pass it as zero. */ - status = krb_sendauth (KOPT_DO_MUTUAL, s, &ticket, "rcmd", - hname, realm, (unsigned long) 0, &msg_data, - &cred, sched, &laddr, &sin, "KCVSV1.0"); - if (status != KSUCCESS) - error (1, 0, "kerberos authentication failed: %s", - krb_get_err_text (status)); - memcpy (kblock, cred.session, sizeof (C_Block)); - } - - close_on_exec (s); - - free (hname); - - /* Give caller the values it wants. */ - make_bufs_from_fds (s, s, 0, to_server, from_server, 1); -} - -#endif /* HAVE_KERBEROS */ - -#ifdef HAVE_GSSAPI - -/* Receive a given number of bytes. */ - -static void -recv_bytes (sock, buf, need) - int sock; - char *buf; - int need; -{ - while (need > 0) - { - int got; - - got = recv (sock, buf, need, 0); - if (got <= 0) - error (1, 0, "recv() from server %s: %s", current_parsed_root->hostname, - got == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO)); - - buf += got; - need -= got; - } -} - -/* Connect to the server using GSSAPI authentication. */ - -/* FIXME - * - * This really needs to be rewritten to use a buffer and not a socket. - * This would enable gserver to work with the SSL code I'm about to commit - * since the SSL connection is going to look like a FIFO and not a socket. - * - * I think, basically, it will need to use buf_output and buf_read directly - * since I don't think there is a read_bytes function - only read_line. - * - * recv_bytes could then be removed too. - * - * Besides, I added some cruft to reenable the socket which shouldn't be - * there. This would also enable its removal. - */ -#define BUFSIZE 1024 -static int -connect_to_gserver (root, sock, hostinfo) - cvsroot_t *root; - int sock; - struct hostent *hostinfo; -{ - char *str; - char buf[BUFSIZE]; - gss_buffer_desc *tok_in_ptr, tok_in, tok_out; - OM_uint32 stat_min, stat_maj; - gss_name_t server_name; - - str = "BEGIN GSSAPI REQUEST\012"; - - if (send (sock, str, strlen (str), 0) < 0) - error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); - - if (strlen (hostinfo->h_name) > BUFSIZE - 5) - error (1, 0, "Internal error: hostname exceeds length of buffer"); - sprintf (buf, "cvs@%s", hostinfo->h_name); - tok_in.length = strlen (buf); - tok_in.value = buf; - gss_import_name (&stat_min, &tok_in, GSS_C_NT_HOSTBASED_SERVICE, - &server_name); - - tok_in_ptr = GSS_C_NO_BUFFER; - gcontext = GSS_C_NO_CONTEXT; - - do - { - stat_maj = gss_init_sec_context (&stat_min, GSS_C_NO_CREDENTIAL, - &gcontext, server_name, - GSS_C_NULL_OID, - (GSS_C_MUTUAL_FLAG - | GSS_C_REPLAY_FLAG), - 0, NULL, tok_in_ptr, NULL, &tok_out, - NULL, NULL); - 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 (&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); - } - - if (tok_out.length == 0) - { - tok_in.length = 0; - } - else - { - char cbuf[2]; - int need; - - cbuf[0] = (tok_out.length >> 8) & 0xff; - cbuf[1] = tok_out.length & 0xff; - if (send (sock, cbuf, 2, 0) < 0) - error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); - if (send (sock, tok_out.value, tok_out.length, 0) < 0) - error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); - - recv_bytes (sock, cbuf, 2); - need = ((cbuf[0] & 0xff) << 8) | (cbuf[1] & 0xff); - - if (need > sizeof buf) - { - ssize_t got; - size_t total; - - /* 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]; - total = 2; - while (got = recv (sock, buf + total, sizeof buf - total, 0)) - { - if (got < 0) - error (1, 0, "recv() from server %s: %s", - root->hostname, SOCK_STRERROR (SOCK_ERRNO)); - total += got; - if (strrchr (buf + total - got, '\n')) - break; - } - buf[total] = '\0'; - if (buf[total - 1] == '\n') - buf[total - 1] = '\0'; - error (1, 0, "error from server %s: %s", root->hostname, - buf); - } - - recv_bytes (sock, buf, need); - tok_in.length = need; - } - - tok_in.value = buf; - tok_in_ptr = &tok_in; - } - while (stat_maj == GSS_S_CONTINUE_NEEDED); - - return 1; -} - -#endif /* HAVE_GSSAPI */ - - - -static int send_variable_proc PROTO ((Node *, void *)); - -static int -send_variable_proc (node, closure) - Node *node; - void *closure; -{ - send_to_server ("Set ", 0); - send_to_server (node->key, 0); - send_to_server ("=", 1); - send_to_server (node->data, 0); - send_to_server ("\012", 1); - return 0; -} - - - -/* Contact the server. */ -void -start_server () -{ - int rootless; - char *log = getenv ("CVS_CLIENT_LOG"); - - /* Clear our static variables for this invocation. */ - if (toplevel_repos != NULL) - free (toplevel_repos); - toplevel_repos = NULL; - - /* Note that generally speaking we do *not* fall back to a different - way of connecting if the first one does not work. This is slow - (*really* slow on a 14.4kbps link); the clean way to have a CVS - which supports several ways of connecting is with access methods. */ - - switch (current_parsed_root->method) - { - -#ifdef AUTH_CLIENT_SUPPORT - case pserver_method: - /* Toss the return value. It will die with an error message if - * anything goes wrong anyway. - */ - connect_to_pserver (current_parsed_root, &to_server, &from_server, 0, 0); - break; -#endif /* AUTH_CLIENT_SUPPORT */ - -#if HAVE_KERBEROS - case kserver_method: - start_tcp_server (current_parsed_root, &to_server, &from_server); - break; -#endif /* HAVE_KERBEROS */ - -#ifdef HAVE_GSSAPI - case gserver_method: - /* GSSAPI authentication is handled by the pserver. */ - connect_to_pserver (current_parsed_root, &to_server, &from_server, 0, 1); - break; -#endif /* HAVE_GSSAPI */ - - case ext_method: - case extssh_method: -#ifdef NO_EXT_METHOD - error (0, 0, ":ext: method not supported by this port of CVS"); - error (1, 0, "try :server: instead"); -#else /* ! NO_EXT_METHOD */ - start_rsh_server (current_parsed_root, &to_server, &from_server); -#endif /* NO_EXT_METHOD */ - break; - - case server_method: -#ifdef START_SERVER - { - int tofd, fromfd; - START_SERVER (&tofd, &fromfd, getcaller (), - current_parsed_root->username, current_parsed_root->hostname, - current_parsed_root->directory); -# ifdef START_SERVER_RETURNS_SOCKET - make_bufs_from_fds (tofd, fromfd, 0, &to_server, &from_server, 1); -# else /* ! START_SERVER_RETURNS_SOCKET */ - make_bufs_from_fds (tofd, fromfd, 0, &to_server, &from_server, 0); -# endif /* START_SERVER_RETURNS_SOCKET */ - } -#else /* ! START_SERVER */ - /* FIXME: It should be possible to implement this portably, - like pserver, which would get rid of the duplicated code - in {vms,windows-NT,...}/startserver.c. */ - error (1, 0, -"the :server: access method is not supported by this port of CVS"); -#endif /* START_SERVER */ - break; - - case fork_method: - connect_to_forked_server (&to_server, &from_server); - break; - - default: - error (1, 0, "\ -(start_server internal error): unknown access method"); - break; - } - - /* "Hi, I'm Darlene and I'll be your server tonight..." */ - server_started = 1; - - /* Set up logfiles, if any. - * - * We do this _after_ authentication on purpose. Wouldn't really like to - * worry about logging passwords... - */ - if (log) - { - int len = strlen (log); - char *buf = xmalloc (len + 5); - char *p; - FILE *fp; - - strcpy (buf, log); - p = buf + len; - - /* Open logfiles in binary mode so that they reflect - exactly what was transmitted and received (that is - more important than that they be maximally - convenient to view). */ - /* Note that if we create several connections in a single CVS client - (currently used by update.c), then the last set of logfiles will - overwrite the others. There is currently no way around this. */ - strcpy (p, ".in"); - fp = open_file (buf, "wb"); - if (fp == NULL) - error (0, errno, "opening to-server logfile %s", buf); - else - to_server = log_buffer_initialize (to_server, fp, 0, - (BUFMEMERRPROC) NULL); - - strcpy (p, ".out"); - fp = open_file (buf, "wb"); - if (fp == NULL) - error (0, errno, "opening from-server logfile %s", buf); - else - from_server = log_buffer_initialize (from_server, fp, 1, - (BUFMEMERRPROC) NULL); - - free (buf); - } - - /* Clear static variables. */ - if (toplevel_repos != NULL) - free (toplevel_repos); - toplevel_repos = NULL; - if (last_repos != NULL) - free (last_repos); - last_repos = NULL; - if (last_update_dir != NULL) - free (last_update_dir); - last_update_dir = NULL; - stored_checksum_valid = 0; - if (stored_mode != NULL) - { - free (stored_mode); - stored_mode = NULL; - } - - rootless = (strcmp (cvs_cmd_name, "init") == 0); - if (!rootless) - { - send_to_server ("Root ", 0); - send_to_server (current_parsed_root->directory, 0); - send_to_server ("\012", 1); - } - - { - struct response *rs; - - send_to_server ("Valid-responses", 0); - - for (rs = responses; rs->name != NULL; ++rs) - { - send_to_server (" ", 0); - send_to_server (rs->name, 0); - } - send_to_server ("\012", 1); - } - send_to_server ("valid-requests\012", 0); - - if (get_server_responses ()) - error_exit (); - - /* - * Now handle global options. - * - * -H, -f, -d, -e should be handled OK locally. - * - * -b we ignore (treating it as a server installation issue). - * FIXME: should be an error message. - * - * -v we print local version info; FIXME: Add a protocol request to get - * the version from the server so we can print that too. - * - * -l -t -r -w -q -n and -Q need to go to the server. - */ - - { - int have_global = supported_request ("Global_option"); - - if (noexec) - { - if (have_global) - { - send_to_server ("Global_option -n\012", 0); - } - else - error (1, 0, - "This server does not support the global -n option."); - } - if (quiet) - { - if (have_global) - { - send_to_server ("Global_option -q\012", 0); - } - else - error (1, 0, - "This server does not support the global -q option."); - } - if (really_quiet) - { - if (have_global) - { - send_to_server ("Global_option -Q\012", 0); - } - else - error (1, 0, - "This server does not support the global -Q option."); - } - if (!cvswrite) - { - if (have_global) - { - send_to_server ("Global_option -r\012", 0); - } - else - error (1, 0, - "This server does not support the global -r option."); - } - if (trace) - { - if (have_global) - { - send_to_server ("Global_option -t\012", 0); - } - else - error (1, 0, - "This server does not support the global -t option."); - } - } - - /* Find out about server-side cvswrappers. An extra network - turnaround for cvs import seems to be unavoidable, unless we - want to add some kind of client-side place to configure which - filenames imply binary. For cvs add, we could avoid the - problem by keeping a copy of the wrappers in CVSADM (the main - reason to bother would be so we could make add work without - contacting the server, I suspect). */ - - if ((strcmp (cvs_cmd_name, "import") == 0) - || (strcmp (cvs_cmd_name, "add") == 0)) - { - if (supported_request ("wrapper-sendme-rcsOptions")) - { - int err; - send_to_server ("wrapper-sendme-rcsOptions\012", 0); - err = get_server_responses (); - if (err != 0) - error (err, 0, "error reading from server"); - } - } - - if (cvsencrypt && !rootless) - { -#ifdef ENCRYPTION - /* Turn on encryption before turning on compression. We do - not want to try to compress the encrypted stream. Instead, - we want to encrypt the compressed stream. If we can't turn - on encryption, bomb out; don't let the user think the data - is being encrypted when it is not. */ -#ifdef HAVE_KERBEROS - if (current_parsed_root->method == kserver_method) - { - if (! supported_request ("Kerberos-encrypt")) - error (1, 0, "This server does not support encryption"); - send_to_server ("Kerberos-encrypt\012", 0); - to_server = krb_encrypt_buffer_initialize (to_server, 0, sched, - kblock, - (BUFMEMERRPROC) NULL); - from_server = krb_encrypt_buffer_initialize (from_server, 1, - sched, kblock, - (BUFMEMERRPROC) NULL); - } - else -#endif /* HAVE_KERBEROS */ -#ifdef HAVE_GSSAPI - if (current_parsed_root->method == gserver_method) - { - if (! supported_request ("Gssapi-encrypt")) - error (1, 0, "This server does not support encryption"); - send_to_server ("Gssapi-encrypt\012", 0); - to_server = cvs_gssapi_wrap_buffer_initialize (to_server, 0, - gcontext, - ((BUFMEMERRPROC) - NULL)); - from_server = cvs_gssapi_wrap_buffer_initialize (from_server, 1, - gcontext, - ((BUFMEMERRPROC) - NULL)); - cvs_gssapi_encrypt = 1; - } - else -#endif /* HAVE_GSSAPI */ - error (1, 0, "Encryption is only supported when using GSSAPI or Kerberos"); -#else /* ! ENCRYPTION */ - error (1, 0, "This client does not support encryption"); -#endif /* ! ENCRYPTION */ - } - - if (gzip_level && !rootless) - { - if (supported_request ("Gzip-stream")) - { - char gzip_level_buf[5]; - send_to_server ("Gzip-stream ", 0); - sprintf (gzip_level_buf, "%d", gzip_level); - send_to_server (gzip_level_buf, 0); - send_to_server ("\012", 1); - - /* All further communication with the server will be - compressed. */ - - to_server = compress_buffer_initialize (to_server, 0, gzip_level, - (BUFMEMERRPROC) NULL); - from_server = compress_buffer_initialize (from_server, 1, - gzip_level, - (BUFMEMERRPROC) NULL); - } -#ifndef NO_CLIENT_GZIP_PROCESS - else if (supported_request ("gzip-file-contents")) - { - char gzip_level_buf[5]; - send_to_server ("gzip-file-contents ", 0); - sprintf (gzip_level_buf, "%d", gzip_level); - send_to_server (gzip_level_buf, 0); - - send_to_server ("\012", 1); - - file_gzip_level = gzip_level; - } -#endif - else - { - fprintf (stderr, "server doesn't support gzip-file-contents\n"); - /* Setting gzip_level to 0 prevents us from giving the - error twice if update has to contact the server again - to fetch unpatchable files. */ - gzip_level = 0; - } - } - - if (cvsauthenticate && ! cvsencrypt && !rootless) - { - /* Turn on authentication after turning on compression, so - that we can compress the authentication information. We - assume that encrypted data is always authenticated--the - ability to decrypt the data stream is itself a form of - authentication. */ -#ifdef HAVE_GSSAPI - if (current_parsed_root->method == gserver_method) - { - if (! supported_request ("Gssapi-authenticate")) - error (1, 0, - "This server does not support stream authentication"); - send_to_server ("Gssapi-authenticate\012", 0); - to_server = cvs_gssapi_wrap_buffer_initialize (to_server, 0, - gcontext, - ((BUFMEMERRPROC) - NULL)); - from_server = cvs_gssapi_wrap_buffer_initialize (from_server, 1, - gcontext, - ((BUFMEMERRPROC) - NULL)); - } - else - error (1, 0, "Stream authentication is only supported when using GSSAPI"); -#else /* ! HAVE_GSSAPI */ - error (1, 0, "This client does not support stream authentication"); -#endif /* ! HAVE_GSSAPI */ - } - - /* If "Set" is not supported, just silently fail to send the variables. - Users with an old server should get a useful error message when it - fails to recognize the ${=foo} syntax. This way if someone uses - several servers, some of which are new and some old, they can still - set user variables in their .cvsrc without trouble. */ - if (supported_request ("Set")) - walklist (variable_list, send_variable_proc, NULL); -} - - - -#ifndef NO_EXT_METHOD - -/* Contact the server by starting it with rsh. */ - -/* Right now, we have two different definitions for this function, - depending on whether we start the rsh server using popenRW or not. - This isn't ideal, and the best thing would probably be to change - the OS/2 port to be more like the regular Unix client (i.e., by - implementing piped_child)... but I'm doing something else at the - moment, and wish to make only one change at a time. -Karl */ - -# ifdef START_RSH_WITH_POPEN_RW - -/* This is actually a crock -- it's OS/2-specific, for no one else - uses it. If I get time, I want to make piped_child and all the - other stuff in os2/run.c work right. In the meantime, this gets us - up and running, and that's most important. */ - -static void -start_rsh_server (root, to_server, from_server) - cvsroot_t *root; - struct buffer **to_server; - struct buffer **from_server; -{ - int pipes[2]; - int child_pid; - - /* If you're working through firewalls, you can set the - CVS_RSH environment variable to a script which uses rsh to - invoke another rsh on a proxy machine. */ - char *env_cvs_rsh = getenv ("CVS_RSH"); - char *env_cvs_ssh = getenv ("CVS_SSH"); - char *cvs_rsh; - char *cvs_server = getenv ("CVS_SERVER"); - int i = 0; - /* This needs to fit "rsh", "-b", "-l", "USER", "host", - "cmd (w/ args)", and NULL. We leave some room to grow. */ - char *rsh_argv[10]; - - if (root->method == extssh_method) - cvs_rsh = env_cvs_ssh ? env_cvs_ssh : SSH_DFLT; - else - cvs_rsh = env_cvs_rsh ? env_cvs_rsh : RSH_DFLT; - - if (!cvs_server) - cvs_server = "cvs"; - - /* The command line starts out with rsh. */ - rsh_argv[i++] = cvs_rsh; - -# ifdef RSH_NEEDS_BINARY_FLAG - /* "-b" for binary, under OS/2. */ - rsh_argv[i++] = "-b"; -# endif /* RSH_NEEDS_BINARY_FLAG */ - - /* Then we strcat more things on the end one by one. */ - if (root->username != NULL) - { - rsh_argv[i++] = "-l"; - rsh_argv[i++] = root->username; - } - - rsh_argv[i++] = root->hostname; - rsh_argv[i++] = cvs_server; - rsh_argv[i++] = "server"; - - /* Mark the end of the arg list. */ - rsh_argv[i] = (char *) NULL; - - if (trace) - { - fprintf (stderr, " -> Starting server: "); - for (i = 0; rsh_argv[i]; i++) - fprintf (stderr, "%s ", rsh_argv[i]); - putc ('\n', stderr); - } - - /* Do the deed. */ - child_pid = popenRW (rsh_argv, pipes); - if (child_pid < 0) - error (1, errno, "cannot start server via rsh"); - - /* Give caller the file descriptors in a form it can deal with. */ - make_bufs_from_fds (pipes[0], pipes[1], child_pid, to_server, from_server, 0); -} - -# else /* ! START_RSH_WITH_POPEN_RW */ - -static void -start_rsh_server (root, to_server, from_server) - cvsroot_t *root; - struct buffer **to_server; - struct buffer **from_server; -{ - /* If you're working through firewalls, you can set the - CVS_RSH environment variable to a script which uses rsh to - invoke another rsh on a proxy machine. */ - char *env_cvs_rsh = getenv ("CVS_RSH"); - char *env_cvs_ssh = getenv ("CVS_SSH"); - char *cvs_rsh; - char *cvs_server = getenv ("CVS_SERVER"); - char *command; - int tofd, fromfd; - int child_pid; - - if (root->method == extssh_method) - cvs_rsh = env_cvs_ssh ? env_cvs_ssh : SSH_DFLT; - else - cvs_rsh = env_cvs_rsh ? env_cvs_rsh : RSH_DFLT; - - if (!cvs_server) - cvs_server = "cvs"; - - /* Pass the command to rsh as a single string. This shouldn't - affect most rsh servers at all, and will pacify some buggy - versions of rsh that grab switches out of the middle of the - command (they're calling the GNU getopt routines incorrectly). */ - command = xmalloc (strlen (cvs_server) + 8); - - /* If you are running a very old (Nov 3, 1994, before 1.5) - * version of the server, you need to make sure that your .bashrc - * on the server machine does not set CVSROOT to something - * containing a colon (or better yet, upgrade the server). */ - sprintf (command, "%s server", cvs_server); - - { - const char *argv[10]; - const char **p = argv; - - *p++ = cvs_rsh; - - /* If the login names differ between client and server - * pass it on to rsh. - */ - if (root->username != NULL) - { - *p++ = "-l"; - *p++ = root->username; - } - - *p++ = root->hostname; - *p++ = command; - *p++ = NULL; - - if (trace) - { - int i; - - fprintf (stderr, " -> Starting server: "); - for (i = 0; argv[i]; i++) - fprintf (stderr, "%s ", argv[i]); - putc ('\n', stderr); - } - child_pid = piped_child (argv, &tofd, &fromfd, 1); - - if (child_pid < 0) - error (1, errno, "cannot start server via rsh"); - } - free (command); - - make_bufs_from_fds (tofd, fromfd, child_pid, to_server, from_server, 0); -} - -# endif /* START_RSH_WITH_POPEN_RW */ - -#endif /* NO_EXT_METHOD */ - - - -/* Send an argument STRING. */ -void -send_arg (string) - const char *string; -{ - char buf[1]; - const char *p = string; - - send_to_server ("Argument ", 0); - - while (*p) - { - if (*p == '\n') - { - send_to_server ("\012Argumentx ", 0); - } - else - { - buf[0] = *p; - send_to_server (buf, 1); - } - ++p; - } - send_to_server ("\012", 1); -} - - - -static void send_modified PROTO ((const char *, const char *, Vers_TS *)); - -/* VERS->OPTIONS specifies whether the file is binary or not. NOTE: BEFORE - using any other fields of the struct vers, we would need to fix - client_process_import_file to set them up. */ - -static void -send_modified (file, short_pathname, vers) - const char *file; - const char *short_pathname; - Vers_TS *vers; -{ - /* File was modified, send it. */ - struct stat sb; - int fd; - char *buf; - char *mode_string; - size_t bufsize; - int bin; - - if (trace) - (void) fprintf (stderr, " -> Sending file `%s' to server\n", file); - - /* Don't think we can assume fstat exists. */ - if ( CVS_STAT (file, &sb) < 0) - error (1, errno, "reading %s", short_pathname); - - mode_string = mode_to_string (sb.st_mode); - - /* Beware: on systems using CRLF line termination conventions, - the read and write functions will convert CRLF to LF, so the - number of characters read is not the same as sb.st_size. Text - files should always be transmitted using the LF convention, so - we don't want to disable this conversion. */ - bufsize = sb.st_size; - buf = xmalloc (bufsize); - - /* Is the file marked as containing binary data by the "-kb" flag? - If so, make sure to open it in binary mode: */ - - if (vers && vers->options) - bin = !(strcmp (vers->options, "-kb")); - else - bin = 0; - -#ifdef BROKEN_READWRITE_CONVERSION - if (!bin) - { - /* If only stdio, not open/write/etc., do text/binary - conversion, use convert_file which can compensate - (FIXME: we could just use stdio instead which would - avoid the whole problem). */ - char tfile[1024]; strcpy(tfile, file); strcat(tfile, ".CVSBFCTMP"); - convert_file (file, O_RDONLY, - tfile, O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY); - fd = CVS_OPEN (tfile, O_RDONLY | OPEN_BINARY); - if (fd < 0) - error (1, errno, "reading %s", short_pathname); - } - else - fd = CVS_OPEN (file, O_RDONLY | OPEN_BINARY); -#else - fd = CVS_OPEN (file, O_RDONLY | (bin ? OPEN_BINARY : 0)); -#endif - - if (fd < 0) - error (1, errno, "reading %s", short_pathname); - - if (file_gzip_level && sb.st_size > 100) - { - size_t newsize = 0; - - if (read_and_gzip (fd, short_pathname, (unsigned char **)&buf, - &bufsize, &newsize, - file_gzip_level)) - error (1, 0, "aborting due to compression error"); - - if (close (fd) < 0) - error (0, errno, "warning: can't close %s", short_pathname); - - { - char tmp[80]; - - send_to_server ("Modified ", 0); - send_to_server (file, 0); - send_to_server ("\012", 1); - send_to_server (mode_string, 0); - send_to_server ("\012z", 2); - sprintf (tmp, "%lu\n", (unsigned long) newsize); - send_to_server (tmp, 0); - - send_to_server (buf, newsize); - } - } - else - { - int newsize; - - { - char *bufp = buf; - int len; - - /* FIXME: This is gross. It assumes that we might read - less than st_size bytes (true on NT), but not more. - Instead of this we should just be reading a block of - data (e.g. 8192 bytes), writing it to the network, and - so on until EOF. */ - while ((len = read (fd, bufp, (buf + sb.st_size) - bufp)) > 0) - bufp += len; - - if (len < 0) - error (1, errno, "reading %s", short_pathname); - - newsize = bufp - buf; - } - if (close (fd) < 0) - error (0, errno, "warning: can't close %s", short_pathname); - - { - char tmp[80]; - - send_to_server ("Modified ", 0); - send_to_server (file, 0); - send_to_server ("\012", 1); - send_to_server (mode_string, 0); - send_to_server ("\012", 1); - sprintf (tmp, "%lu\012", (unsigned long) newsize); - send_to_server (tmp, 0); - } -#ifdef BROKEN_READWRITE_CONVERSION - if (!bin) - { - char tfile[1024]; strcpy(tfile, file); strcat(tfile, ".CVSBFCTMP"); - if (CVS_UNLINK (tfile) < 0) - error (0, errno, "warning: can't remove temp file %s", tfile); - } -#endif - - /* - * Note that this only ends with a newline if the file ended with - * one. - */ - if (newsize > 0) - send_to_server (buf, newsize); - } - free (buf); - free (mode_string); -} - -/* The address of an instance of this structure is passed to - send_fileproc, send_filesdoneproc, and send_direntproc, as the - callerdat parameter. */ - -struct send_data -{ - /* Each of the following flags are zero for clear or nonzero for set. */ - int build_dirs; - int force; - int no_contents; - int backup_modified; -}; - -static int send_fileproc PROTO ((void *callerdat, struct file_info *finfo)); - -/* Deal with one file. */ -static int -send_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - struct send_data *args = (struct send_data *) callerdat; - Vers_TS *vers; - struct file_info xfinfo; - /* File name to actually use. Might differ in case from - finfo->file. */ - const char *filename; - - send_a_repository ("", finfo->repository, finfo->update_dir); - - xfinfo = *finfo; - xfinfo.repository = NULL; - xfinfo.rcs = NULL; - vers = Version_TS (&xfinfo, NULL, NULL, NULL, 0, 0); - - if (vers->entdata != NULL) - filename = vers->entdata->user; - else - filename = finfo->file; - - if (vers->vn_user != NULL) - { - /* The Entries request. */ - send_to_server ("Entry /", 0); - send_to_server (filename, 0); - send_to_server ("/", 0); - send_to_server (vers->vn_user, 0); - send_to_server ("/", 0); - if (vers->ts_conflict != NULL) - { - if (vers->ts_user != NULL && - strcmp (vers->ts_conflict, vers->ts_user) == 0) - send_to_server ("+=", 0); - else - send_to_server ("+modified", 0); - } - send_to_server ("/", 0); - send_to_server (vers->entdata != NULL - ? vers->entdata->options - : vers->options, - 0); - send_to_server ("/", 0); - if (vers->entdata != NULL && vers->entdata->tag) - { - send_to_server ("T", 0); - send_to_server (vers->entdata->tag, 0); - } - else if (vers->entdata != NULL && vers->entdata->date) - { - send_to_server ("D", 0); - send_to_server (vers->entdata->date, 0); - } - send_to_server ("\012", 1); - } - else - { - /* It seems a little silly to re-read this on each file, but - send_dirent_proc doesn't get called if filenames are specified - explicitly on the command line. */ - wrap_add_file (CVSDOTWRAPPER, 1); - - if (wrap_name_has (filename, WRAP_RCSOPTION)) - { - /* No "Entry", but the wrappers did give us a kopt so we better - send it with "Kopt". As far as I know this only happens - for "cvs add". Question: is there any reason why checking - for options from wrappers isn't done in Version_TS? - - Note: it might have been better to just remember all the - kopts on the client side, rather than send them to the server, - and have it send us back the same kopts. But that seemed like - a bigger change than I had in mind making now. */ - - if (supported_request ("Kopt")) - { - char *opt; - - send_to_server ("Kopt ", 0); - opt = wrap_rcsoption (filename, 1); - send_to_server (opt, 0); - send_to_server ("\012", 1); - free (opt); - } - else - error (0, 0, - "\ -warning: ignoring -k options due to server limitations"); - } - } - - if (vers->ts_user == NULL) - { - /* - * Do we want to print "file was lost" like normal CVS? - * Would it always be appropriate? - */ - /* File no longer exists. Don't do anything, missing files - just happen. */ - } - else if (vers->ts_rcs == NULL - || args->force - || strcmp (vers->ts_conflict - && supported_request ("Empty-conflicts") - ? vers->ts_conflict : vers->ts_rcs, vers->ts_user) - || (vers->ts_conflict && !strcmp (cvs_cmd_name, "diff")) - || (vers->vn_user && *vers->vn_user == '0')) - { - if (args->no_contents - && supported_request ("Is-modified")) - { - send_to_server ("Is-modified ", 0); - send_to_server (filename, 0); - send_to_server ("\012", 1); - } - 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 - { - send_to_server ("Unchanged ", 0); - send_to_server (filename, 0); - send_to_server ("\012", 1); - } - - /* if this directory has an ignore list, add this file to it */ - if (ignlist) - { - Node *p; - - p = getnode (); - p->type = FILES; - p->key = xstrdup (finfo->file); - (void) addnode (ignlist, p); - } - - freevers_ts (&vers); - return 0; -} - - - -static void send_ignproc PROTO ((const char *, const char *)); - -static void -send_ignproc (file, dir) - const char *file; - const char *dir; -{ - if (ign_inhibit_server || !supported_request ("Questionable")) - { - if (dir[0] != '\0') - (void) printf ("? %s/%s\n", dir, file); - else - (void) printf ("? %s\n", file); - } - else - { - send_to_server ("Questionable ", 0); - send_to_server (file, 0); - send_to_server ("\012", 1); - } -} - - - -static int send_filesdoneproc PROTO ((void *, int, const char *, const char *, - List *)); - -static int -send_filesdoneproc (callerdat, err, repository, update_dir, entries) - void *callerdat; - int err; - const char *repository; - const char *update_dir; - List *entries; -{ - /* if this directory has an ignore list, process it then free it */ - if (ignlist) - { - ignore_files (ignlist, entries, update_dir, send_ignproc); - dellist (&ignlist); - } - - return (err); -} - -static Dtype send_dirent_proc PROTO ((void *, const char *, const char *, - const char *, List *)); - -/* - * send_dirent_proc () is called back by the recursion processor before a - * sub-directory is processed for update. - * A return code of 0 indicates the directory should be - * processed by the recursion code. A return of non-zero indicates the - * recursion code should skip this directory. - * - */ -static Dtype -send_dirent_proc (callerdat, dir, repository, update_dir, entries) - void *callerdat; - const char *dir; - const char *repository; - const char *update_dir; - List *entries; -{ - struct send_data *args = (struct send_data *) callerdat; - int dir_exists; - char *cvsadm_name; - - if (ignore_directory (update_dir)) - { - /* print the warm fuzzy message */ - if (!quiet) - error (0, 0, "Ignoring %s", update_dir); - return (R_SKIP_ALL); - } - - /* - * If the directory does not exist yet (e.g. "cvs update -d foo"), - * no need to send any files from it. If the directory does not - * have a CVS directory, then we pretend that it does not exist. - * Otherwise, we will fail when trying to open the Entries file. - * This case will happen when checking out a module defined as - * ``-a .''. - */ - cvsadm_name = xmalloc (strlen (dir) + sizeof (CVSADM) + 10); - sprintf (cvsadm_name, "%s/%s", dir, CVSADM); - dir_exists = isdir (cvsadm_name); - free (cvsadm_name); - - /* - * 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. - */ - - if (dir_exists) - { - /* - * Get the repository from a CVS/Repository file whenever possible. - * The repository variable is wrong if the names in the local - * directory don't match the names in the repository. - */ - 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 - { - /* It doesn't make sense to send a non-existent directory, - because there is no way to get the correct value for - the repository (I suppose maybe via the expand-modules - request). In the case where the "obvious" choice for - repository is correct, the server can figure out whether - to recreate the directory; in the case where it is wrong - (that is, does not match what modules give us), we might as - well just fail to recreate it. - - Checking for noexec is a kludge for "cvs -n add dir". */ - /* Don't send a non-existent directory unless we are building - new directories (build_dirs is true). Otherwise, CVS may - see a D line in an Entries file, and recreate a directory - which the user removed by hand. */ - if (args->build_dirs && noexec) - send_a_repository (dir, repository, update_dir); - } - - return (dir_exists ? R_PROCESS : R_SKIP_ALL); -} - - - -static int send_dirleave_proc PROTO ((void *, const char *, int, const 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; - const char *dir; - int err; - const 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 an array to the server, one by one. - * argv might be "--foo=bar", "-C", "5", "-y". - */ -void -send_options (int argc, char *const *argv) -{ - int i; - for (i = 0; i < argc; i++) - send_arg (argv[i]); -} - - - -/* Send the names of all the argument files to the server. */ -void -send_file_names (argc, argv, flags) - int argc; - char **argv; - unsigned int flags; -{ - int i; - - /* The fact that we do this here as well as start_recursion is a bit - of a performance hit. Perhaps worth cleaning up someday. */ - if (flags & SEND_EXPAND_WILD) - expand_wild (argc, argv, &argc, &argv); - - for (i = 0; i < argc; ++i) - { - char buf[1]; - char *p; -#ifdef FILENAMES_CASE_INSENSITIVE - char *line = xmalloc (1); - *line = '\0'; -#endif /* FILENAMES_CASE_INSENSITIVE */ - - if (arg_should_not_be_sent_to_server (argv[i])) - continue; - -#ifdef FILENAMES_CASE_INSENSITIVE - /* We want to send the path as it appears in the - CVS/Entries files. We put this inside an ifdef - to avoid doing all these system calls in - cases where fncmp is just strcmp anyway. */ - /* The isdir (CVSADM) check could more gracefully be replaced - with a way of having Entries_Open report back the - error to us and letting us ignore existence_error. - Or some such. */ - { - List *stack; - size_t line_len = 0; - char *q, *r; - struct saved_cwd sdir; - - /* Split the argument onto the stack. */ - stack = getlist(); - r = xstrdup (argv[i]); - /* It's okay to discard the const from the last_component return - * below since we know we passed in an arg that was not const. - */ - while ((q = (char *)last_component (r)) != r) - { - push (stack, xstrdup (q)); - *--q = '\0'; - } - push (stack, r); - - /* Normalize the path into outstr. */ - save_cwd (&sdir); - while (q = pop (stack)) - { - Node *node = NULL; - if (isdir (CVSADM)) - { - List *entries; - - /* Note that if we are adding a directory, - the following will read the entry - that we just wrote there, that is, we - will get the case specified on the - command line, not the case of the - directory in the filesystem. This - is correct behavior. */ - entries = Entries_Open (0, NULL); - node = findnode_fn (entries, q); - if (node != NULL) - { - /* Add the slash unless this is our first element. */ - if (line_len) - xrealloc_and_strcat (&line, &line_len, "/"); - xrealloc_and_strcat (&line, &line_len, node->key); - delnode (node); - } - Entries_Close (entries); - } - - /* If node is still NULL then we either didn't find CVSADM or - * we didn't find an entry there. - */ - if (node == NULL) - { - /* Add the slash unless this is our first element. */ - if (line_len) - xrealloc_and_strcat (&line, &line_len, "/"); - xrealloc_and_strcat (&line, &line_len, q); - break; - } - - /* And descend the tree. */ - if (isdir (q)) - CVS_CHDIR (q); - free (q); - } - restore_cwd (&sdir, NULL); - free_cwd (&sdir); - - /* Now put everything we didn't find entries for back on. */ - while (q = pop (stack)) - { - if (line_len) - xrealloc_and_strcat (&line, &line_len, "/"); - xrealloc_and_strcat (&line, &line_len, q); - free (q); - } - - p = line; - - dellist (&stack); - } -#else /* !FILENAMES_CASE_INSENSITIVE */ - p = argv[i]; -#endif /* FILENAMES_CASE_INSENSITIVE */ - - send_to_server ("Argument ", 0); - - while (*p) - { - if (*p == '\n') - { - send_to_server ("\012Argumentx ", 0); - } - else if (ISDIRSEP (*p)) - { - buf[0] = '/'; - send_to_server (buf, 1); - } - else - { - buf[0] = *p; - send_to_server (buf, 1); - } - ++p; - } - send_to_server ("\012", 1); -#ifdef FILENAMES_CASE_INSENSITIVE - free (line); -#endif /* FILENAMES_CASE_INSENSITIVE */ - } - - if (flags & SEND_EXPAND_WILD) - { - int i; - for (i = 0; i < argc; ++i) - free (argv[i]); - free (argv); - } -} - - - -/* Calculate and send max-dotdot to the server */ -static void -send_max_dotdot (argc, argv) - int argc; - char **argv; -{ - int i; - int level = 0; - int max_level = 0; - - /* Send Max-dotdot if needed. */ - for (i = 0; i < argc; ++i) - { - level = pathname_levels (argv[i]); - if (level > 0) - { - if (uppaths == NULL) uppaths = getlist(); - push_string (uppaths, xstrdup (argv[i])); - } - if (level > max_level) - max_level = level; - } - - if (max_level > 0) - { - if (supported_request ("Max-dotdot")) - { - char buf[10]; - sprintf (buf, "%d", max_level); - - send_to_server ("Max-dotdot ", 0); - send_to_server (buf, 0); - send_to_server ("\012", 1); - } - else - { - error (1, 0, -"backreference in path (`..') not supported by old (pre-Max-dotdot) servers"); - } - } -} - - - -/* Send Repository, Modified and Entry. argc and argv contain only - the files to operate on (or empty for everything), not options. - local is nonzero if we should not recurse (-l option). flags & - SEND_BUILD_DIRS is nonzero if nonexistent directories should be - sent. flags & SEND_FORCE is nonzero if we should send unmodified - files to the server as though they were modified. flags & - SEND_NO_CONTENTS means that this command only needs to know - _whether_ a file is modified, not the contents. Also sends Argument - lines for argc and argv, so should be called after options are sent. */ -void -send_files (argc, argv, local, aflag, flags) - int argc; - char **argv; - int local; - int aflag; - unsigned int flags; -{ - struct send_data args; - int err; - - send_max_dotdot (argc, argv); - - /* - * aflag controls whether the tag/date is copied into the vers_ts. - * But we don't actually use it, so I don't think it matters what we pass - * for aflag here. - */ - 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, send_dirleave_proc, (void *) &args, - argc, argv, local, W_LOCAL, aflag, CVS_LOCK_NONE, (char *) NULL, 0, - (char *) NULL); - if (err) - error_exit (); - if (toplevel_repos == NULL) - /* - * This happens if we are not processing any files, - * or for checkouts in directories without any existing stuff - * checked out. The following assignment is correct for the - * latter case; I don't think toplevel_repos matters for the - * former. - */ - toplevel_repos = xstrdup (current_parsed_root->directory); - send_repository ("", toplevel_repos, "."); -} - -void -client_import_setup (repository) - char *repository; -{ - if (toplevel_repos == NULL) /* should always be true */ - send_a_repository ("", repository, ""); -} - -/* - * Process the argument import file. - */ -int -client_process_import_file (message, vfile, vtag, targc, targv, repository, - all_files_binary, modtime) - char *message; - char *vfile; - char *vtag; - int targc; - char *targv[]; - char *repository; - int all_files_binary; - - /* Nonzero for "import -d". */ - int modtime; -{ - char *update_dir; - char *fullname; - Vers_TS vers; - - assert (toplevel_repos != NULL); - - if (strncmp (repository, toplevel_repos, strlen (toplevel_repos)) != 0) - error (1, 0, - "internal error: pathname `%s' doesn't specify file in `%s'", - repository, toplevel_repos); - - if (strcmp (repository, toplevel_repos) == 0) - { - update_dir = ""; - fullname = xstrdup (vfile); - } - else - { - update_dir = repository + strlen (toplevel_repos) + 1; - - fullname = xmalloc (strlen (vfile) + strlen (update_dir) + 10); - strcpy (fullname, update_dir); - strcat (fullname, "/"); - strcat (fullname, vfile); - } - - send_a_repository ("", repository, update_dir); - if (all_files_binary) - { - vers.options = xmalloc (4); /* strlen("-kb") + 1 */ - strcpy (vers.options, "-kb"); - } - else - { - vers.options = wrap_rcsoption (vfile, 1); - } - if (vers.options != NULL) - { - if (supported_request ("Kopt")) - { - send_to_server ("Kopt ", 0); - send_to_server (vers.options, 0); - send_to_server ("\012", 1); - } - else - error (0, 0, - "warning: ignoring -k options due to server limitations"); - } - if (modtime) - { - if (supported_request ("Checkin-time")) - { - struct stat sb; - char *rcsdate; - char netdate[MAXDATELEN]; - - if (CVS_STAT (vfile, &sb) < 0) - error (1, errno, "cannot stat %s", fullname); - rcsdate = date_from_time_t (sb.st_mtime); - date_to_internet (netdate, rcsdate); - free (rcsdate); - - send_to_server ("Checkin-time ", 0); - send_to_server (netdate, 0); - send_to_server ("\012", 1); - } - else - error (0, 0, - "warning: ignoring -d option due to server limitations"); - } - send_modified (vfile, fullname, &vers); - if (vers.options != NULL) - free (vers.options); - free (fullname); - return 0; -} - -void -client_import_done () -{ - if (toplevel_repos == NULL) - /* - * This happens if we are not processing any files, - * or for checkouts in directories without any existing stuff - * checked out. The following assignment is correct for the - * latter case; I don't think toplevel_repos matters for the - * former. - */ - /* FIXME: "can't happen" now that we call client_import_setup - at the beginning. */ - toplevel_repos = xstrdup (current_parsed_root->directory); - send_repository ("", toplevel_repos, "."); -} - - - -static void -notified_a_file (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - FILE *fp; - FILE *newf; - size_t line_len = 8192; - char *line = xmalloc (line_len); - char *cp; - int nread; - int nwritten; - char *p; - - fp = open_file (CVSADM_NOTIFY, "r"); - if (getline (&line, &line_len, fp) < 0) - { - if (feof (fp)) - error (0, 0, "cannot read %s: end of file", CVSADM_NOTIFY); - else - error (0, errno, "cannot read %s", CVSADM_NOTIFY); - goto error_exit; - } - cp = strchr (line, '\t'); - if (cp == NULL) - { - error (0, 0, "malformed %s file", CVSADM_NOTIFY); - goto error_exit; - } - *cp = '\0'; - if (strcmp (filename, line + 1) != 0) - { - error (0, 0, "protocol error: notified %s, expected %s", filename, - line + 1); - } - - if (getline (&line, &line_len, fp) < 0) - { - if (feof (fp)) - { - free (line); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", CVSADM_NOTIFY); - if ( CVS_UNLINK (CVSADM_NOTIFY) < 0) - error (0, errno, "cannot remove %s", CVSADM_NOTIFY); - return; - } - else - { - error (0, errno, "cannot read %s", CVSADM_NOTIFY); - goto error_exit; - } - } - newf = open_file (CVSADM_NOTIFYTMP, "w"); - if (fputs (line, newf) < 0) - { - error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP); - goto error2; - } - while ((nread = fread (line, 1, line_len, fp)) > 0) - { - p = line; - while ((nwritten = fwrite (p, 1, nread, newf)) > 0) - { - nread -= nwritten; - p += nwritten; - } - if (ferror (newf)) - { - error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP); - goto error2; - } - } - if (ferror (fp)) - { - error (0, errno, "cannot read %s", CVSADM_NOTIFY); - goto error2; - } - if (fclose (newf) < 0) - { - error (0, errno, "cannot close %s", CVSADM_NOTIFYTMP); - goto error_exit; - } - free (line); - if (fclose (fp) < 0) - { - error (0, errno, "cannot close %s", CVSADM_NOTIFY); - return; - } - - { - /* In this case, we want rename_file() to ignore noexec. */ - int saved_noexec = noexec; - noexec = 0; - rename_file (CVSADM_NOTIFYTMP, CVSADM_NOTIFY); - noexec = saved_noexec; - } - - return; - error2: - (void) fclose (newf); - error_exit: - free (line); - (void) fclose (fp); -} - -static void -handle_notified (args, len) - char *args; - int len; -{ - call_in_directory (args, notified_a_file, NULL); -} - -void -client_notify (repository, update_dir, filename, notif_type, val) - const char *repository; - const char *update_dir; - const char *filename; - int notif_type; - const char *val; -{ - char buf[2]; - - send_a_repository ("", repository, update_dir); - send_to_server ("Notify ", 0); - send_to_server (filename, 0); - send_to_server ("\012", 1); - buf[0] = notif_type; - buf[1] = '\0'; - send_to_server (buf, 1); - send_to_server ("\t", 1); - send_to_server (val, 0); -} - -/* - * Send an option with an argument, dealing correctly with newlines in - * the argument. If ARG is NULL, forget the whole thing. - */ -void -option_with_arg (option, arg) - char *option; - char *arg; -{ - if (arg == NULL) - return; - - send_to_server ("Argument ", 0); - send_to_server (option, 0); - send_to_server ("\012", 1); - - send_arg (arg); -} - -/* Send a date to the server. The input DATE is in RCS format. - The time will be GMT. - - We then convert that to the format required in the protocol - (including the "-D" option) and send it. According to - cvsclient.texi, RFC 822/1123 format is preferred. */ - -void -client_senddate (date) - const char *date; -{ - char buf[MAXDATELEN]; - - date_to_internet (buf, (char *)date); - option_with_arg ("-D", buf); -} - -void -send_init_command () -{ - /* This is here because we need the current_parsed_root->directory variable. */ - send_to_server ("init ", 0); - send_to_server (current_parsed_root->directory, 0); - send_to_server ("\012", 0); -} - -#endif /* CLIENT_SUPPORT */ diff --git a/contrib/cvs/src/client.h b/contrib/cvs/src/client.h deleted file mode 100644 index 9afa4e7..0000000 --- a/contrib/cvs/src/client.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 1994-2008 The Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* Interface between the client and the rest of CVS. */ - -/* Stuff shared with the server. */ -extern char *mode_to_string PROTO((mode_t)); -extern int change_mode PROTO((char *, char *, int)); - -extern int gzip_level; -extern int file_gzip_level; - -#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) - -/* Whether the connection should be encrypted. */ -extern int cvsencrypt; - -/* Whether the connection should use per-packet authentication. */ -extern int cvsauthenticate; - -#ifdef __STDC__ -struct buffer; -#endif - -# ifdef ENCRYPTION - -# ifdef HAVE_KERBEROS - -/* We can't declare the arguments without including krb.h, and I don't - want to do that in every file. */ -extern struct buffer *krb_encrypt_buffer_initialize (); - -# endif /* HAVE_KERBEROS */ - -# ifdef HAVE_GSSAPI - -/* Set this to turn on GSSAPI encryption. */ -extern int cvs_gssapi_encrypt; - -# endif /* HAVE_GSSAPI */ - -# endif /* ENCRYPTION */ - -# ifdef HAVE_GSSAPI - -/* We can't declare the arguments without including gssapi.h, and I - don't want to do that in every file. */ -extern struct buffer *cvs_gssapi_wrap_buffer_initialize (); - -# endif /* HAVE_GSSAPI */ - -#endif /* defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */ - -#ifdef CLIENT_SUPPORT -/* - * Flag variable for seeing whether the server has been started yet. - * As of this writing, only edit.c:cvs_notify_check() uses it. - */ -extern int server_started; - -/* Is the -P option to checkout or update specified? */ -extern int client_prune_dirs; - -# ifdef AUTH_CLIENT_SUPPORT -extern int use_authenticating_server; -# endif /* AUTH_CLIENT_SUPPORT */ -# if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI) -void connect_to_pserver PROTO ((cvsroot_t *, - struct buffer **, - struct buffer **, - int, int )); -# ifndef CVS_AUTH_PORT -# define CVS_AUTH_PORT 2401 -# endif /* CVS_AUTH_PORT */ -# endif /* (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI) */ - -# if HAVE_KERBEROS -# ifndef CVS_PORT -# define CVS_PORT 1999 -# endif -# endif /* HAVE_KERBEROS */ - -/* Talking to the server. */ -void send_to_server PROTO((const char *str, size_t len)); -void read_from_server PROTO((char *buf, size_t len)); - -/* Internal functions that handle client communication to server, etc. */ -int supported_request PROTO ((char *)); -void option_with_arg PROTO((char *option, char *arg)); - -/* Get the responses and then close the connection. */ -extern int get_responses_and_close PROTO((void)); - -extern int get_server_responses PROTO((void)); - -/* Start up the connection to the server on the other end. */ -void -start_server PROTO((void)); - -/* Send the names of all the argument files to the server. */ -void -send_file_names PROTO((int argc, char **argv, unsigned int flags)); - -/* Flags for send_file_names. */ -/* Expand wild cards? */ -# define SEND_EXPAND_WILD 1 - -/* - * Send Repository, Modified and Entry. argc and argv contain only - * the files to operate on (or empty for everything), not options. - * local is nonzero if we should not recurse (-l option). - */ -void -send_files PROTO((int argc, char **argv, int local, int aflag, - unsigned int flags)); - -/* Flags for send_files. */ -# 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 -send_arg PROTO((const char *string)); - -/* Send a string of single-char options to the remote server, one by one. */ -void send_options PROTO ((int argc, char * const *argv)); - -extern void send_a_repository PROTO ((const char *, const char *, - const char *)); - -#endif /* CLIENT_SUPPORT */ - -/* - * This structure is used to catalog the responses the client is - * prepared to see from the server. - */ - -struct response -{ - /* Name of the response. */ - char *name; - -#ifdef CLIENT_SUPPORT - /* - * Function to carry out the response. ARGS is the text of the - * command after name and, if present, a single space, have been - * stripped off. The function can scribble into ARGS if it wants. - * Note that although LEN is given, ARGS is also guaranteed to be - * '\0' terminated. - */ - void (*func) PROTO((char *args, int len)); - - /* - * ok and error are special; they indicate we are at the end of the - * responses, and error indicates we should exit with nonzero - * exitstatus. - */ - enum {response_type_normal, response_type_ok, response_type_error} type; -#endif - - /* Used by the server to indicate whether response is supported by - the client, as set by the Valid-responses request. */ - enum { - /* - * Failure to implement this response can imply a fatal - * error. This should be set only for responses which were in the - * original version of the protocol; it should not be set for new - * responses. - */ - rs_essential, - - /* Some clients might not understand this response. */ - rs_optional, - - /* - * Set by the server to one of the following based on what this - * client actually supports. - */ - rs_supported, - rs_not_supported - } status; -}; - -/* Table of responses ending in an entry with a NULL name. */ - -extern struct response responses[]; - -#ifdef CLIENT_SUPPORT - -extern void client_senddate PROTO((const char *date)); -extern void client_expand_modules PROTO((int argc, char **argv, int local)); -extern void client_send_expansions PROTO((int local, char *where, - int build_dirs)); -extern void client_nonexpanded_setup PROTO((void)); - -extern void send_init_command PROTO ((void)); - -extern char **failed_patches; -extern int failed_patches_count; -extern char *toplevel_wd; -extern void client_import_setup PROTO((char *repository)); -extern int client_process_import_file - PROTO((char *message, char *vfile, char *vtag, - int targc, char *targv[], char *repository, int all_files_binary, - int modtime)); -extern void client_import_done PROTO((void)); -extern void client_notify PROTO((const char *, const char *, const char *, int, - const char *)); -#endif /* CLIENT_SUPPORT */ diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c deleted file mode 100644 index b3ba47b..0000000 --- a/contrib/cvs/src/commit.c +++ /dev/null @@ -1,2433 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Commit Files - * - * "commit" commits the present version to the RCS repository, AFTER - * having done a test on conflicts. - * - * The call is: cvs commit [options] files... - * - * $FreeBSD$ - */ - -#include <assert.h> -#include "cvs.h" -#include "getline.h" -#include "edit.h" -#include "fileattr.h" -#include "hardlink.h" - -static Dtype check_direntproc PROTO ((void *callerdat, const char *dir, - const char *repos, - const char *update_dir, - List *entries)); -static int check_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static int check_filesdoneproc PROTO ((void *callerdat, int err, - const char *repos, - const char *update_dir, - List *entries)); -static int checkaddfile PROTO((const char *file, const char *repository, - const char *tag, const char *options, - RCSNode **rcsnode)); -static Dtype commit_direntproc PROTO ((void *callerdat, const char *dir, - const char *repos, - const char *update_dir, - List *entries)); -static int commit_dirleaveproc PROTO ((void *callerdat, const char *dir, - int err, const char *update_dir, - List *entries)); -static int commit_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static int commit_filesdoneproc PROTO ((void *callerdat, int err, - const char *repository, - const char *update_dir, - List *entries)); -static int finaladd PROTO((struct file_info *finfo, char *revision, char *tag, - char *options)); -static int findmaxrev PROTO((Node * p, void *closure)); -static int lock_RCS PROTO((const char *user, RCSNode *rcs, const char *rev, - const char *repository)); -static int precommit_list_proc PROTO((Node * p, void *closure)); -static int precommit_proc PROTO((const char *repository, const char *filter)); -static int remove_file PROTO ((struct file_info *finfo, char *tag, - char *message)); -static void fixaddfile PROTO((const char *rcs)); -static void fixbranch PROTO((RCSNode *, char *branch)); -static void unlockrcs PROTO((RCSNode *rcs)); -static void ci_delproc PROTO((Node *p)); -static void masterlist_delproc PROTO((Node *p)); - -struct commit_info -{ - Ctype status; /* as returned from Classify_File() */ - char *rev; /* a numeric rev, if we know it */ - char *tag; /* any sticky tag, or -r option */ - char *options; /* Any sticky -k option */ -}; -struct master_lists -{ - List *ulist; /* list for Update_Logfile */ - List *cilist; /* list with commit_info structs */ -}; - -static int force_ci = 0; -static int got_message; -static int aflag; -static char *saved_tag; -static char *write_dirtag; -static int write_dirnonbranch; -static char *logfile; -static List *mulist; -static List *saved_ulist; -static char *saved_message; -static time_t last_register_time; - -static const char *const commit_usage[] = -{ - "Usage: %s %s [-Rlf] [-m msg | -F logfile] [-r rev] files...\n", - " -R Process directories recursively.\n", - " -l Local directory only (not recursive).\n", - " -f Force the file to be committed; disables recursion.\n", - " -F logfile Read the log message from file.\n", - " -m msg Log message.\n", - " -r rev Commit to this branch or trunk revision.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -#ifdef CLIENT_SUPPORT -/* Identify a file which needs "? foo" or a Questionable request. */ -struct question { - /* The two fields for the Directory request. */ - char *dir; - char *repos; - - /* The file name. */ - char *file; - - struct question *next; -}; - -struct find_data { - List *ulist; - int argc; - char **argv; - - /* This is used from dirent to filesdone time, for each directory, - to make a list of files we have already seen. */ - List *ignlist; - - /* Linked list of files which need "? foo" or a Questionable request. */ - struct question *questionables; - - /* Only good within functions called from the filesdoneproc. Stores - the repository (pointer into storage managed by the recursion - processor. */ - const char *repository; - - /* Non-zero if we should force the commit. This is enabled by - either -f or -r options, unlike force_ci which is just -f. */ - int force; -}; - - - -static Dtype find_dirent_proc PROTO ((void *callerdat, const char *dir, - const char *repository, - const char *update_dir, - List *entries)); - -static Dtype -find_dirent_proc (callerdat, dir, repository, update_dir, entries) - void *callerdat; - const char *dir; - const char *repository; - const char *update_dir; - List *entries; -{ - struct find_data *find_data = (struct find_data *)callerdat; - - /* This check seems to slowly be creeping throughout CVS (update - and send_dirent_proc by CVS 1.5, diff in 31 Oct 1995. My guess - is that it (or some variant thereof) should go in all the - dirent procs. Unless someone has some better idea... */ - if (!isdir (dir)) - return R_SKIP_ALL; - - /* initialize the ignore list for this directory */ - find_data->ignlist = getlist (); - - /* Print the same warm fuzzy as in check_direntproc, since that - code will never be run during client/server operation and we - want the messages to match. */ - if (!quiet) - error (0, 0, "Examining %s", update_dir); - - return R_PROCESS; -} - - - -/* Here as a static until we get around to fixing ignore_files to pass - it along as an argument. */ -static struct find_data *find_data_static; - - - -static void find_ignproc PROTO ((const char *, const char *)); - -static void -find_ignproc (file, dir) - const char *file; - const char *dir; -{ - struct question *p; - - p = (struct question *) xmalloc (sizeof (struct question)); - p->dir = xstrdup (dir); - p->repos = xstrdup (find_data_static->repository); - p->file = xstrdup (file); - p->next = find_data_static->questionables; - find_data_static->questionables = p; -} - - - -static int find_filesdoneproc PROTO ((void *callerdat, int err, - const char *repository, - const char *update_dir, - List *entries)); - -static int -find_filesdoneproc (callerdat, err, repository, update_dir, entries) - void *callerdat; - int err; - const char *repository; - const char *update_dir; - List *entries; -{ - struct find_data *find_data = (struct find_data *)callerdat; - find_data->repository = repository; - - /* if this directory has an ignore list, process it then free it */ - if (find_data->ignlist) - { - find_data_static = find_data; - ignore_files (find_data->ignlist, entries, update_dir, find_ignproc); - dellist (&find_data->ignlist); - } - - find_data->repository = NULL; - - return err; -} - - - -static int find_fileproc PROTO ((void *callerdat, struct file_info *finfo)); - -/* Machinery to find out what is modified, added, and removed. It is - possible this should be broken out into a new client_classify function; - merging it with classify_file is almost sure to be a mess, though, - because classify_file has all kinds of repository processing. */ -static int -find_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - Vers_TS *vers; - enum classify_type status; - Node *node; - struct find_data *args = (struct find_data *)callerdat; - struct logfile_info *data; - struct file_info xfinfo; - - /* if this directory has an ignore list, add this file to it */ - if (args->ignlist) - { - Node *p; - - p = getnode (); - p->type = FILES; - p->key = xstrdup (finfo->file); - if (addnode (args->ignlist, p) != 0) - freenode (p); - } - - xfinfo = *finfo; - xfinfo.repository = NULL; - xfinfo.rcs = NULL; - - vers = Version_TS (&xfinfo, NULL, saved_tag, NULL, 0, 0); - if (vers->vn_user == NULL) - { - if (vers->ts_user == NULL) - error (0, 0, "nothing known about `%s'", finfo->fullname); - else - error (0, 0, "use `%s add' to create an entry for %s", - program_name, finfo->fullname); - freevers_ts (&vers); - return 1; - } - if (vers->vn_user[0] == '-') - { - if (vers->ts_user != NULL) - { - error (0, 0, - "`%s' should be removed and is still there (or is back" - " again)", finfo->fullname); - freevers_ts (&vers); - return 1; - } - /* else */ - status = T_REMOVED; - } - else if (strcmp (vers->vn_user, "0") == 0) - { - if (vers->ts_user == NULL) - { - /* This happens when one has `cvs add'ed a file, but it no - longer exists in the working directory at commit time. - FIXME: What classify_file does in this case is print - "new-born %s has disappeared" and removes the entry. - We probably should do the same. */ - if (!really_quiet) - error (0, 0, "warning: new-born %s has disappeared", - finfo->fullname); - status = T_REMOVE_ENTRY; - } - else - status = T_ADDED; - } - else if (vers->ts_user == NULL) - { - /* FIXME: What classify_file does in this case is print - "%s was lost". We probably should do the same. */ - freevers_ts (&vers); - return 0; - } - else if (vers->ts_rcs != NULL - && (args->force || strcmp (vers->ts_user, vers->ts_rcs) != 0)) - /* If we are forcing commits, pretend that the file is - modified. */ - status = T_MODIFIED; - else - { - /* This covers unmodified files, as well as a variety of other - 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; - } - - node = getnode (); - node->key = xstrdup (finfo->fullname); - - data = (struct logfile_info *) xmalloc (sizeof (struct logfile_info)); - data->type = status; - data->tag = xstrdup (vers->tag); - data->rev_old = data->rev_new = NULL; - - node->type = UPDATE; - node->delproc = update_delproc; - node->data = data; - (void)addnode (args->ulist, node); - - ++args->argc; - - freevers_ts (&vers); - return 0; -} - - - -static int copy_ulist PROTO ((Node *, void *)); - -static int -copy_ulist (node, data) - Node *node; - void *data; -{ - struct find_data *args = (struct find_data *)data; - args->argv[args->argc++] = node->key; - return 0; -} -#endif /* CLIENT_SUPPORT */ - -#ifdef SERVER_SUPPORT -# define COMMIT_OPTIONS "+nlRm:fF:r:" -#else /* !SERVER_SUPPORT */ -# define COMMIT_OPTIONS "+lRm:fF:r:" -#endif /* SERVER_SUPPORT */ -int -commit (argc, argv) - int argc; - char **argv; -{ - int c; - int err = 0; - int local = 0; - - if (argc == -1) - usage (commit_usage); - -#ifdef CVS_BADROOT - /* - * For log purposes, do not allow "root" to commit files. If you look - * like root, but are really logged in as a non-root user, it's OK. - */ - /* FIXME: Shouldn't this check be much more closely related to the - readonly user stuff (CVSROOT/readers, &c). That is, why should - root be able to "cvs init", "cvs import", &c, but not "cvs ci"? */ - /* Who we are on the client side doesn't affect logging. */ - if (geteuid () == (uid_t) 0 && !current_parsed_root->isremote) - { - struct passwd *pw; - - if ((pw = (struct passwd *) getpwnam (getcaller ())) == NULL) - error (1, 0, - "your apparent username (%s) is unknown to this system", - getcaller ()); - if (pw->pw_uid == (uid_t) 0) - error (1, 0, "'root' is not allowed to commit files"); - } -#endif /* CVS_BADROOT */ - - optind = 0; - while ((c = getopt (argc, argv, COMMIT_OPTIONS)) != -1) - { - switch (c) - { -#ifdef SERVER_SUPPORT - case 'n': - /* Silently ignore -n for compatibility with old - * clients. - */ - if (!server_active) error(0, 0, "the `-n' option is obsolete"); - break; -#endif /* SERVER_SUPPORT */ - case 'm': -#ifdef FORCE_USE_EDITOR - use_editor = 1; -#else - use_editor = 0; -#endif - if (saved_message) - { - free (saved_message); - saved_message = NULL; - } - - saved_message = xstrdup(optarg); - break; - case 'r': - if (saved_tag) - free (saved_tag); - saved_tag = xstrdup (optarg); - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'f': - force_ci = 1; - local = 1; /* also disable recursion */ - break; - case 'F': -#ifdef FORCE_USE_EDITOR - use_editor = 1; -#else - use_editor = 0; -#endif - logfile = optarg; - break; - case '?': - default: - usage (commit_usage); - break; - } - } - argc -= optind; - argv += optind; - - /* numeric specified revision means we ignore sticky tags... */ - if (saved_tag && isdigit ((unsigned char) *saved_tag)) - { - char *p = saved_tag + strlen (saved_tag); - aflag = 1; - /* strip trailing dots and leading zeros */ - while (*--p == '.') ; - p[1] = '\0'; - while (saved_tag[0] == '0' && isdigit ((unsigned char) saved_tag[1])) - ++saved_tag; - } - - /* some checks related to the "-F logfile" option */ - if (logfile) - { - size_t size = 0, len; - - if (saved_message) - error (1, 0, "cannot specify both a message and a log file"); - - get_file (logfile, logfile, "r", &saved_message, &size, &len); - } - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - struct find_data find_args; - - ign_setup (); - - find_args.ulist = getlist (); - find_args.argc = 0; - find_args.questionables = NULL; - find_args.ignlist = NULL; - find_args.repository = NULL; - - /* It is possible that only a numeric tag should set this. - I haven't really thought about it much. - Anyway, I suspect that setting it unnecessarily only causes - a little unneeded network traffic. */ - find_args.force = force_ci || saved_tag != NULL; - - err = start_recursion (find_fileproc, find_filesdoneproc, - find_dirent_proc, (DIRLEAVEPROC) NULL, - (void *)&find_args, - argc, argv, local, W_LOCAL, 0, CVS_LOCK_NONE, - (char *) NULL, 0, (char *) NULL); - if (err) - 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. - This saves time--we don't want to search the file system - of the working directory twice. */ - if (size_overflow_p (xtimes (find_args.argc, sizeof (char **)))) - { - find_args.argc = 0; - return 0; - } - find_args.argv = xmalloc (xtimes (find_args.argc, sizeof (char **))); - find_args.argc = 0; - walklist (find_args.ulist, copy_ulist, &find_args); - - /* Do this before calling do_editor; don't ask for a log - message if we can't talk to the server. But do it after we - have made the checks that we can locally (to more quickly - catch syntax errors, the case where no files are modified, - added or removed, etc.). - - On the other hand, calling start_server before do_editor - means that we chew up server resources the whole time that - the user has the editor open (hours or days if the user - forgets about it), which seems dubious. */ - start_server (); - - /* - * We do this once, not once for each directory as in normal CVS. - * The protocol is designed this way. This is a feature. - */ - if (use_editor) - do_editor (".", &saved_message, (char *)NULL, find_args.ulist); - - /* We always send some sort of message, even if empty. */ - option_with_arg ("-m", saved_message ? saved_message : ""); - - /* OK, now process all the questionable files we have been saving - up. */ - { - struct question *p; - struct question *q; - - p = find_args.questionables; - while (p != NULL) - { - if (ign_inhibit_server || !supported_request ("Questionable")) - { - cvs_output ("? ", 2); - if (p->dir[0] != '\0') - { - cvs_output (p->dir, 0); - cvs_output ("/", 1); - } - cvs_output (p->file, 0); - cvs_output ("\n", 1); - } - else - { - send_to_server ("Directory ", 0); - send_to_server (p->dir[0] == '\0' ? "." : p->dir, 0); - send_to_server ("\012", 1); - send_to_server (p->repos, 0); - send_to_server ("\012", 1); - - send_to_server ("Questionable ", 0); - send_to_server (p->file, 0); - send_to_server ("\012", 1); - } - free (p->dir); - free (p->repos); - free (p->file); - q = p->next; - free (p); - p = q; - } - } - - if (local) - send_arg("-l"); - if (force_ci) - send_arg("-f"); - option_with_arg ("-r", saved_tag); - send_arg ("--"); - - /* FIXME: This whole find_args.force/SEND_FORCE business is a - kludge. It would seem to be a server bug that we have to - say that files are modified when they are not. This makes - "cvs commit -r 2" across a whole bunch of files a very slow - operation (and it isn't documented in cvsclient.texi). I - haven't looked at the server code carefully enough to be - _sure_ why this is needed, but if it is because the "ci" - program, which we used to call, wanted the file to exist, - then it would be relatively simple to fix in the server. */ - send_files (find_args.argc, find_args.argv, local, 0, - find_args.force ? SEND_FORCE : 0); - - /* Sending only the names of the files which were modified, added, - or removed means that the server will only do an up-to-date - check on those files. This is different from local CVS and - 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 (); - if (err != 0 && use_editor && saved_message != NULL) - { - /* If there was an error, don't nuke the user's carefully - constructed prose. This is something of a kludge; a better - solution is probably more along the lines of #150 in TODO - (doing a second up-to-date check before accepting the - log message has also been suggested, but that seems kind of - iffy because the real up-to-date check could still fail, - another error could occur, &c. Also, a second check would - slow things down). */ - - char *fname; - FILE *fp; - - fp = cvs_temp_file (&fname); - if (fp == NULL) - error (1, 0, "cannot create temporary file %s", - fname ? fname : "(null)"); - if (fwrite (saved_message, 1, strlen (saved_message), fp) - != strlen (saved_message)) - error (1, errno, "cannot write temporary file %s", fname); - if (fclose (fp) < 0) - error (0, errno, "cannot close temporary file %s", fname); - error (0, 0, "saving log message in %s", fname); - free (fname); - } - return err; - } -#endif - - if (saved_tag != NULL) - tag_check_valid (saved_tag, argc, argv, local, aflag, ""); - - /* XXX - this is not the perfect check for this */ - if (argc <= 0) - write_dirtag = saved_tag; - - wrap_setup (); - - lock_tree_for_write (argc, argv, local, W_LOCAL, aflag); - - /* - * Set up the master update list and hard link list - */ - mulist = getlist (); - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - if (preserve_perms) - { - hardlist = getlist (); - - /* - * We need to save the working directory so that - * check_fileproc can construct a full pathname for each file. - */ - working_dir = xgetwd(); - } -#endif - - /* - * Run the recursion processor to verify the files are all up-to-date - */ - err = start_recursion (check_fileproc, check_filesdoneproc, - check_direntproc, (DIRLEAVEPROC) NULL, NULL, argc, - argv, local, W_LOCAL, aflag, CVS_LOCK_NONE, - (char *) NULL, 1, (char *) NULL); - if (err) - { - Lock_Cleanup (); - error (1, 0, "correct above errors first!"); - } - - /* - * Run the recursion processor to commit the files - */ - write_dirnonbranch = 0; - if (noexec == 0) - err = start_recursion (commit_fileproc, commit_filesdoneproc, - commit_direntproc, commit_dirleaveproc, NULL, - argc, argv, local, W_LOCAL, aflag, CVS_LOCK_NONE, - (char *) NULL, 1, (char *) NULL); - - /* - * Unlock all the dirs and clean up - */ - Lock_Cleanup (); - dellist (&mulist); - - if (server_active) - return err; - - /* see if we need to sleep before returning to avoid time-stamp races */ - if (last_register_time) - { - sleep_past (last_register_time); - } - - return err; -} - - - -/* This routine determines the status of a given file and retrieves - the version information that is associated with that file. */ - -static -Ctype -classify_file_internal (finfo, vers) - struct file_info *finfo; - Vers_TS **vers; -{ - int save_noexec, save_quiet, save_really_quiet; - Ctype status; - - /* FIXME: Do we need to save quiet as well as really_quiet? Last - time I glanced at Classify_File I only saw it looking at really_quiet - not quiet. */ - save_noexec = noexec; - save_quiet = quiet; - save_really_quiet = really_quiet; - noexec = quiet = really_quiet = 1; - - /* handle specified numeric revision specially */ - if (saved_tag && isdigit ((unsigned char) *saved_tag)) - { - /* If the tag is for the trunk, make sure we're at the head */ - if (numdots (saved_tag) < 2) - { - status = Classify_File (finfo, (char *) NULL, (char *) NULL, - (char *) NULL, 1, aflag, vers, 0); - if (status == T_UPTODATE || status == T_MODIFIED || - status == T_ADDED) - { - Ctype xstatus; - - freevers_ts (vers); - xstatus = Classify_File (finfo, saved_tag, (char *) NULL, - (char *) NULL, 1, aflag, vers, 0); - if (xstatus == T_REMOVE_ENTRY) - status = T_MODIFIED; - else if (status == T_MODIFIED && xstatus == T_CONFLICT) - status = T_MODIFIED; - else - status = xstatus; - } - } - else - { - char *xtag, *cp; - - /* - * The revision is off the main trunk; make sure we're - * up-to-date with the head of the specified branch. - */ - xtag = xstrdup (saved_tag); - if ((numdots (xtag) & 1) != 0) - { - cp = strrchr (xtag, '.'); - *cp = '\0'; - } - status = Classify_File (finfo, xtag, (char *) NULL, - (char *) NULL, 1, aflag, vers, 0); - if ((status == T_REMOVE_ENTRY || status == T_CONFLICT) - && (cp = strrchr (xtag, '.')) != NULL) - { - /* pluck one more dot off the revision */ - *cp = '\0'; - freevers_ts (vers); - status = Classify_File (finfo, xtag, (char *) NULL, - (char *) NULL, 1, aflag, vers, 0); - if (status == T_UPTODATE || status == T_REMOVE_ENTRY) - status = T_MODIFIED; - } - /* now, muck with vers to make the tag correct */ - free ((*vers)->tag); - (*vers)->tag = xstrdup (saved_tag); - free (xtag); - } - } - else - status = Classify_File (finfo, saved_tag, (char *) NULL, (char *) NULL, - 1, 0, vers, 0); - noexec = save_noexec; - quiet = save_quiet; - really_quiet = save_really_quiet; - - return status; -} - - - -/* - * Check to see if a file is ok to commit and make sure all files are - * up-to-date - */ -/* ARGSUSED */ -static int -check_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - Ctype status; - const char *xdir; - Node *p; - List *ulist, *cilist; - Vers_TS *vers; - struct commit_info *ci; - struct logfile_info *li; - - size_t cvsroot_len = strlen (current_parsed_root->directory); - - if (!finfo->repository) - { - error (0, 0, "nothing known about `%s'", finfo->fullname); - return 1; - } - - if (strncmp (finfo->repository, current_parsed_root->directory, - cvsroot_len) == 0 - && ISDIRSEP (finfo->repository[cvsroot_len]) - && strncmp (finfo->repository + cvsroot_len + 1, - CVSROOTADM, - sizeof (CVSROOTADM) - 1) == 0 - && ISDIRSEP (finfo->repository[cvsroot_len + sizeof (CVSROOTADM)]) - && strcmp (finfo->repository + cvsroot_len + sizeof (CVSROOTADM) + 1, - CVSNULLREPOS) == 0 - ) - error (1, 0, "cannot check in to %s", finfo->repository); - - status = classify_file_internal (finfo, &vers); - - /* - * If the force-commit option is enabled, and the file in question - * appears to be up-to-date, just make it look modified so that - * it will be committed. - */ - if (force_ci && status == T_UPTODATE) - status = T_MODIFIED; - - switch (status) - { - case T_CHECKOUT: - case T_PATCH: - case T_NEEDS_MERGE: - case T_REMOVE_ENTRY: - error (0, 0, "Up-to-date check failed for `%s'", finfo->fullname); - freevers_ts (&vers); - return 1; - case T_CONFLICT: - case T_MODIFIED: - case T_ADDED: - case T_REMOVED: - /* - * some quick sanity checks; if no numeric -r option specified: - * - can't have a sticky date - * - can't have a sticky tag that is not a branch - * Also, - * - if status is T_REMOVED, file must not exist and its entry - * can't have a numeric sticky tag. - * - if status is T_ADDED, rcs file must not exist unless on - * a branch or head is dead - * - if status is T_ADDED, can't have a non-trunk numeric rev - * - if status is T_MODIFIED and a Conflict marker exists, don't - * allow the commit if timestamp is identical or if we find - * an RCS_MERGE_PAT in the file. - */ - if (!saved_tag || !isdigit ((unsigned char) *saved_tag)) - { - if (vers->date) - { - error (0, 0, - "cannot commit with sticky date for file `%s'", - finfo->fullname); - freevers_ts (&vers); - return 1; - } - if (status == T_MODIFIED && vers->tag && - !RCS_isbranch (finfo->rcs, vers->tag)) - { - error (0, 0, - "sticky tag `%s' for file `%s' is not a branch", - vers->tag, finfo->fullname); - freevers_ts (&vers); - return 1; - } - } - if (status == T_CONFLICT && !force_ci) - { - error (0, 0, - "file `%s' had a conflict and has not been modified", - finfo->fullname); - freevers_ts (&vers); - return 1; - } - if (status == T_MODIFIED && !force_ci && file_has_markers (finfo)) - { - /* Make this a warning, not an error, because we have - no way of knowing whether the "conflict indicators" - are really from a conflict or whether they are part - of the document itself (cvs.texinfo and sanity.sh in - CVS itself, for example, tend to want to have strings - like ">>>>>>>" at the start of a line). Making people - kludge this the way they need to kludge keyword - expansion seems undesirable. And it is worse than - keyword expansion, because there is no -ko - analogue. */ - error (0, 0, - "\ -warning: file `%s' seems to still contain conflict indicators", - finfo->fullname); - } - - if (status == T_REMOVED) - { - if (vers->ts_user != NULL) - { - error (0, 0, - "`%s' should be removed and is still there (or is" - " back again)", finfo->fullname); - freevers_ts (&vers); - return 1; - } - - if (vers->tag && isdigit ((unsigned char) *vers->tag)) - { - /* Remove also tries to forbid this, but we should check - here. I'm only _sure_ about somewhat obscure cases - (hacking the Entries file, using an old version of - CVS for the remove and a new one for the commit), but - there might be other cases. */ - error (0, 0, - "cannot remove file `%s' which has a numeric sticky" - " tag of `%s'", finfo->fullname, vers->tag); - freevers_ts (&vers); - return 1; - } - } - if (status == T_ADDED) - { - if (vers->tag == NULL) - { - if (finfo->rcs != NULL && - !RCS_isdead (finfo->rcs, finfo->rcs->head)) - { - error (0, 0, - "cannot add file `%s' when RCS file `%s' already exists", - finfo->fullname, finfo->rcs->path); - freevers_ts (&vers); - return 1; - } - } - else if (isdigit ((unsigned char) *vers->tag) && - numdots (vers->tag) > 1) - { - error (0, 0, - "cannot add file `%s' with revision `%s'; must be on trunk", - finfo->fullname, vers->tag); - freevers_ts (&vers); - return 1; - } - } - - /* done with consistency checks; now, to get on with the commit */ - if (finfo->update_dir[0] == '\0') - xdir = "."; - else - xdir = finfo->update_dir; - if ((p = findnode (mulist, xdir)) != NULL) - { - ulist = ((struct master_lists *) p->data)->ulist; - cilist = ((struct master_lists *) p->data)->cilist; - } - else - { - struct master_lists *ml; - - ulist = getlist (); - cilist = getlist (); - p = getnode (); - p->key = xstrdup (xdir); - p->type = UPDATE; - ml = (struct master_lists *) - xmalloc (sizeof (struct master_lists)); - ml->ulist = ulist; - ml->cilist = cilist; - p->data = ml; - p->delproc = masterlist_delproc; - (void) addnode (mulist, p); - } - - /* first do ulist, then cilist */ - p = getnode (); - p->key = xstrdup (finfo->file); - p->type = UPDATE; - p->delproc = update_delproc; - li = ((struct logfile_info *) - xmalloc (sizeof (struct logfile_info))); - li->type = status; - li->tag = xstrdup (vers->tag); - li->rev_old = xstrdup (vers->vn_rcs); - li->rev_new = NULL; - p->data = li; - (void) addnode (ulist, p); - - p = getnode (); - p->key = xstrdup (finfo->file); - p->type = UPDATE; - p->delproc = ci_delproc; - ci = (struct commit_info *) xmalloc (sizeof (struct commit_info)); - ci->status = status; - if (vers->tag) - if (isdigit ((unsigned char) *vers->tag)) - ci->rev = xstrdup (vers->tag); - else - ci->rev = RCS_whatbranch (finfo->rcs, vers->tag); - else - ci->rev = (char *) NULL; - ci->tag = xstrdup (vers->tag); - ci->options = xstrdup(vers->options); - p->data = ci; - (void) addnode (cilist, p); - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - if (preserve_perms) - { - /* Add this file to hardlist, indexed on its inode. When - we are done, we can find out what files are hardlinked - to a given file by looking up its inode in hardlist. */ - char *fullpath; - Node *linkp; - struct hardlink_info *hlinfo; - - /* Get the full pathname of the current file. */ - fullpath = xmalloc (strlen(working_dir) + - strlen(finfo->fullname) + 2); - sprintf (fullpath, "%s/%s", working_dir, finfo->fullname); - - /* To permit following links in subdirectories, files - are keyed on finfo->fullname, not on finfo->name. */ - linkp = lookup_file_by_inode (fullpath); - - /* If linkp is NULL, the file doesn't exist... maybe - we're doing a remove operation? */ - if (linkp != NULL) - { - /* Create a new hardlink_info node, which will record - the current file's status and the links listed in its - `hardlinks' delta field. We will append this - hardlink_info node to the appropriate hardlist entry. */ - hlinfo = (struct hardlink_info *) - xmalloc (sizeof (struct hardlink_info)); - hlinfo->status = status; - linkp->data = hlinfo; - } - } -#endif - - break; - case T_UNKNOWN: - error (0, 0, "nothing known about `%s'", finfo->fullname); - freevers_ts (&vers); - return 1; - case T_UPTODATE: - break; - default: - error (0, 0, "CVS internal error: unknown status %d", status); - break; - } - - freevers_ts (&vers); - return 0; -} - - - -/* - * By default, return the code that tells do_recursion to examine all - * directories - */ -/* ARGSUSED */ -static Dtype -check_direntproc (callerdat, dir, repos, update_dir, entries) - void *callerdat; - const char *dir; - const char *repos; - const char *update_dir; - List *entries; -{ - if (!isdir (dir)) - return R_SKIP_ALL; - - if (!quiet) - error (0, 0, "Examining %s", update_dir); - - return R_PROCESS; -} - - - -/* - * Walklist proc to run pre-commit checks - */ -static int -precommit_list_proc (p, closure) - Node *p; - void *closure; -{ - struct logfile_info *li = p->data; - if (li->type == T_ADDED - || li->type == T_MODIFIED - || li->type == T_REMOVED) - { - run_arg (p->key); - } - return 0; -} - - - -/* - * Callback proc for pre-commit checking - */ -static int -precommit_proc (repository, filter) - const char *repository; - const char *filter; -{ - /* see if the filter is there, only if it's a full path */ - if (isabsolute (filter)) - { - char *s, *cp; - - s = xstrdup (filter); - for (cp = s; *cp; cp++) - if (isspace ((unsigned char) *cp)) - { - *cp = '\0'; - break; - } - if (!isfile (s)) - { - error (0, errno, "cannot find pre-commit filter `%s'", s); - free (s); - return 1; /* so it fails! */ - } - free (s); - } - - run_setup (filter); - run_arg (repository); - (void) walklist (saved_ulist, precommit_list_proc, NULL); - return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY); -} - - - -/* - * Run the pre-commit checks for the dir - */ -/* ARGSUSED */ -static int -check_filesdoneproc (callerdat, err, repos, update_dir, entries) - void *callerdat; - int err; - const char *repos; - const char *update_dir; - List *entries; -{ - int n; - Node *p; - - /* find the update list for this dir */ - p = findnode (mulist, update_dir); - if (p != NULL) - saved_ulist = ((struct master_lists *) p->data)->ulist; - else - saved_ulist = (List *) NULL; - - /* skip the checks if there's nothing to do */ - if (saved_ulist == NULL || saved_ulist->list->next == saved_ulist->list) - return err; - - /* run any pre-commit checks */ - if ((n = Parse_Info (CVSROOTADM_COMMITINFO, repos, precommit_proc, 1)) > 0) - { - error (0, 0, "Pre-commit check failed"); - err += n; - } - - return err; -} - - - -/* - * Do the work of committing a file - */ -static int maxrev; -static char *sbranch; - -/* ARGSUSED */ -static int -commit_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - Node *p; - int err = 0; - List *ulist, *cilist; - struct commit_info *ci; - - /* Keep track of whether write_dirtag is a branch tag. - Note that if it is a branch tag in some files and a nonbranch tag - in others, treat it as a nonbranch tag. It is possible that case - should elicit a warning or an error. */ - if (write_dirtag != NULL - && finfo->rcs != NULL) - { - char *rev = RCS_getversion (finfo->rcs, write_dirtag, NULL, 1, NULL); - if (rev != NULL - && !RCS_nodeisbranch (finfo->rcs, write_dirtag)) - write_dirnonbranch = 1; - if (rev != NULL) - free (rev); - } - - if (finfo->update_dir[0] == '\0') - p = findnode (mulist, "."); - else - p = findnode (mulist, finfo->update_dir); - - /* - * if p is null, there were file type command line args which were - * all up-to-date so nothing really needs to be done - */ - if (p == NULL) - return 0; - ulist = ((struct master_lists *) p->data)->ulist; - cilist = ((struct master_lists *) p->data)->cilist; - - /* - * At this point, we should have the commit message unless we were called - * with files as args from the command line. In that latter case, we - * need to get the commit message ourselves - */ - if (!got_message) - { - got_message = 1; - if (!server_active && use_editor) - do_editor (finfo->update_dir, &saved_message, - finfo->repository, ulist); - do_verify (&saved_message, finfo->repository); - } - - p = findnode (cilist, finfo->file); - if (p == NULL) - return 0; - - ci = p->data; - if (ci->status == T_MODIFIED) - { - if (finfo->rcs == NULL) - error (1, 0, "internal error: no parsed RCS file"); - if (lock_RCS (finfo->file, finfo->rcs, ci->rev, - finfo->repository) != 0) - { - unlockrcs (finfo->rcs); - err = 1; - goto out; - } - } - else if (ci->status == T_ADDED) - { - if (checkaddfile (finfo->file, finfo->repository, ci->tag, ci->options, - &finfo->rcs) != 0) - { - if (finfo->rcs != NULL) - fixaddfile (finfo->rcs->path); - err = 1; - goto out; - } - - /* adding files with a tag, now means adding them on a branch. - Since the branch test was done in check_fileproc for - modified files, we need to stub it in again here. */ - - if (ci->tag - - /* If numeric, it is on the trunk; check_fileproc enforced - this. */ - && !isdigit ((unsigned char) ci->tag[0])) - { - 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, ci->rev, - ci->tag, ci->options, saved_message); - if (err != 0) - { - unlockrcs (finfo->rcs); - fixbranch (finfo->rcs, sbranch); - } - - (void) time (&last_register_time); - - ci->status = T_UPTODATE; - } - } - - /* - * Add the file for real - */ - if (ci->status == T_ADDED) - { - char *xrev = (char *) NULL; - - if (ci->rev == NULL) - { - /* find the max major rev number in this directory */ - maxrev = 0; - (void) walklist (finfo->entries, findmaxrev, NULL); - if (finfo->rcs->head) { - /* resurrecting: include dead revision */ - int thisrev = atoi (finfo->rcs->head); - if (thisrev > maxrev) - maxrev = thisrev; - } - if (maxrev == 0) - maxrev = 1; - xrev = xmalloc (20); - (void) sprintf (xrev, "%d", maxrev); - } - - /* XXX - an added file with symbolic -r should add tag as well */ - err = finaladd (finfo, ci->rev ? ci->rev : xrev, ci->tag, ci->options); - if (xrev) - free (xrev); - } - else if (ci->status == T_MODIFIED) - { - err = Checkin ('M', finfo, ci->rev, ci->tag, - ci->options, saved_message); - - (void) time (&last_register_time); - - if (err != 0) - { - unlockrcs (finfo->rcs); - fixbranch (finfo->rcs, sbranch); - } - } - else if (ci->status == T_REMOVED) - { - err = remove_file (finfo, ci->tag, saved_message); -#ifdef SERVER_SUPPORT - if (server_active) { - server_scratch_entry_only (); - server_updated (finfo, - NULL, - - /* Doesn't matter, it won't get checked. */ - SERVER_UPDATED, - - (mode_t) -1, - (unsigned char *) NULL, - (struct buffer *) NULL); - } -#endif - } - - /* Clearly this is right for T_MODIFIED. I haven't thought so much - about T_ADDED or T_REMOVED. */ - notify_do ('C', finfo->file, getcaller (), NULL, NULL, finfo->repository); - -out: - if (err != 0) - { - /* on failure, remove the file from ulist */ - p = findnode (ulist, finfo->file); - if (p) - delnode (p); - } - else - { - /* On success, retrieve the new version number of the file and - copy it into the log information (see logmsg.c - (logfile_write) for more details). We should only update - the version number for files that have been added or - modified but not removed since classify_file_internal - will return the version number of a file even after it has - been removed from the archive, which is not the behavior we - want for our commitlog messages; we want the old version - number and then "NONE." */ - - if (ci->status != T_REMOVED) - { - p = findnode (ulist, finfo->file); - if (p) - { - Vers_TS *vers; - struct logfile_info *li; - - (void) classify_file_internal (finfo, &vers); - li = p->data; - li->rev_new = xstrdup (vers->vn_rcs); - freevers_ts (&vers); - } - } - } - if (SIG_inCrSect ()) - SIG_endCrSect (); - - return err; -} - - - -/* - * Log the commit and clean up the update list - */ -/* ARGSUSED */ -static int -commit_filesdoneproc (callerdat, err, repository, update_dir, entries) - void *callerdat; - int err; - const char *repository; - const char *update_dir; - List *entries; -{ - Node *p; - List *ulist; - - assert (repository); - - p = findnode (mulist, update_dir); - if (p == NULL) - return err; - - ulist = ((struct master_lists *) p->data)->ulist; - - got_message = 0; - - Update_Logfile (repository, saved_message, (FILE *) 0, ulist); - - /* Build the administrative files if necessary. */ - { - const char *p; - - if (strncmp (current_parsed_root->directory, repository, - strlen (current_parsed_root->directory)) != 0) - error (0, 0, - "internal error: repository (%s) doesn't begin with root (%s)", - repository, current_parsed_root->directory); - p = repository + strlen (current_parsed_root->directory); - if (*p == '/') - ++p; - if (strcmp ("CVSROOT", p) == 0 - /* Check for subdirectories because people may want to create - subdirectories and list files therein in checkoutlist. */ - || strncmp ("CVSROOT/", p, strlen ("CVSROOT/")) == 0 - ) - { - /* "Database" might a little bit grandiose and/or vague, - but "checked-out copies of administrative files, unless - in the case of modules and you are using ndbm in which - case modules.{pag,dir,db}" is verbose and excessively - focused on how the database is implemented. */ - - /* mkmodules requires the absolute name of the CVSROOT directory. - Remove anything after the `CVSROOT' component -- this is - necessary when committing in a subdirectory of CVSROOT. */ - char *admin_dir = xstrdup (repository); - int cvsrootlen = strlen ("CVSROOT"); - assert (admin_dir[p - repository + cvsrootlen] == '\0' - || admin_dir[p - repository + cvsrootlen] == '/'); - admin_dir[p - repository + cvsrootlen] = '\0'; - - cvs_output (program_name, 0); - cvs_output (" ", 1); - cvs_output (cvs_cmd_name, 0); - cvs_output (": Rebuilding administrative file database\n", 0); - mkmodules (admin_dir); - free (admin_dir); - } - } - - return err; -} - - - -/* - * Get the log message for a dir - */ -/* ARGSUSED */ -static Dtype -commit_direntproc (callerdat, dir, repos, update_dir, entries) - void *callerdat; - const char *dir; - const char *repos; - const char *update_dir; - List *entries; -{ - Node *p; - List *ulist; - char *real_repos; - - if (!isdir (dir)) - return R_SKIP_ALL; - - /* find the update list for this dir */ - p = findnode (mulist, update_dir); - if (p != NULL) - ulist = ((struct master_lists *) p->data)->ulist; - else - ulist = (List *) NULL; - - /* skip the files as an optimization */ - if (ulist == NULL || ulist->list->next == ulist->list) - return R_SKIP_FILES; - - /* get commit message */ - real_repos = Name_Repository (dir, update_dir); - got_message = 1; - if (!server_active && use_editor) - do_editor (update_dir, &saved_message, real_repos, ulist); - do_verify (&saved_message, real_repos); - free (real_repos); - return R_PROCESS; -} - - - -/* - * Process the post-commit proc if necessary - */ -/* ARGSUSED */ -static int -commit_dirleaveproc (callerdat, dir, err, update_dir, entries) - void *callerdat; - const char *dir; - int err; - const char *update_dir; - List *entries; -{ - /* update the per-directory tag info */ - /* FIXME? Why? The "commit examples" node of cvs.texinfo briefly - mentions commit -r being sticky, but apparently in the context of - this being a confusing feature! */ - if (err == 0 && write_dirtag != NULL) - { - char *repos = Name_Repository (NULL, update_dir); - WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch, - update_dir, repos); - free (repos); - } - - return err; -} - - - -/* - * find the maximum major rev number in an entries file - */ -static int -findmaxrev (p, closure) - Node *p; - void *closure; -{ - int thisrev; - Entnode *entdata = p->data; - - if (entdata->type != ENT_FILE) - return 0; - thisrev = atoi (entdata->version); - if (thisrev > maxrev) - maxrev = thisrev; - return 0; -} - -/* - * Actually remove a file by moving it to the attic - * XXX - if removing a ,v file that is a relative symbolic link to - * another ,v file, we probably should add a ".." component to the - * link to keep it relative after we move it into the attic. - - Return value is 0 on success, or >0 on error (in which case we have - printed an error message). */ -static int -remove_file (finfo, tag, message) - struct file_info *finfo; - char *tag; - char *message; -{ - int retcode; - - int branch; - int lockflag; - char *corev; - char *rev; - char *prev_rev; - char *old_path; - - corev = NULL; - rev = NULL; - prev_rev = NULL; - - retcode = 0; - - if (finfo->rcs == NULL) - error (1, 0, "internal error: no parsed RCS file"); - - branch = 0; - if (tag && !(branch = RCS_nodeisbranch (finfo->rcs, tag))) - { - /* a symbolic tag is specified; just remove the tag from the file */ - if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0) - { - if (!quiet) - error (0, retcode == -1 ? errno : 0, - "failed to remove tag `%s' from `%s'", tag, - finfo->fullname); - return 1; - } - RCS_rewrite (finfo->rcs, NULL, NULL); - Scratch_Entry (finfo->entries, finfo->file); - return 0; - } - - /* we are removing the file from either the head or a branch */ - /* commit a new, dead revision. */ - - /* Print message indicating that file is going to be removed. */ - cvs_output ("Removing ", 0); - cvs_output (finfo->fullname, 0); - cvs_output (";\n", 0); - - rev = NULL; - lockflag = 1; - if (branch) - { - char *branchname; - - rev = RCS_whatbranch (finfo->rcs, tag); - if (rev == NULL) - { - error (0, 0, "cannot find branch \"%s\".", tag); - return 1; - } - - branchname = RCS_getbranch (finfo->rcs, rev, 1); - if (branchname == NULL) - { - /* no revision exists on this branch. use the previous - revision but do not lock. */ - corev = RCS_gettag (finfo->rcs, tag, 1, (int *) NULL); - prev_rev = xstrdup (corev); - lockflag = 0; - } else - { - corev = xstrdup (rev); - prev_rev = xstrdup (branchname); - free (branchname); - } - - } else /* Not a branch */ - { - /* Get current head revision of file. */ - prev_rev = RCS_head (finfo->rcs); - } - - /* if removing without a tag or a branch, then make sure the default - branch is the trunk. */ - if (!tag && !branch) - { - if (RCS_setbranch (finfo->rcs, NULL) != 0) - { - error (0, 0, "cannot change branch to default for %s", - finfo->fullname); - return 1; - } - RCS_rewrite (finfo->rcs, NULL, NULL); - } - - /* check something out. Generally this is the head. If we have a - particular rev, then name it. */ - retcode = RCS_checkout (finfo->rcs, finfo->file, rev ? corev : NULL, - (char *) NULL, (char *) NULL, RUN_TTY, - (RCSCHECKOUTPROC) NULL, (void *) NULL); - if (retcode != 0) - { - error (0, 0, - "failed to check out `%s'", finfo->fullname); - return 1; - } - - /* Except when we are creating a branch, lock the revision so that - we can check in the new revision. */ - if (lockflag) - { - if (RCS_lock (finfo->rcs, rev ? corev : NULL, 1) == 0) - RCS_rewrite (finfo->rcs, NULL, NULL); - } - - if (corev != NULL) - free (corev); - - retcode = RCS_checkin (finfo->rcs, finfo->file, message, rev, 0, - RCS_FLAGS_DEAD | RCS_FLAGS_QUIET); - if (retcode != 0) - { - if (!quiet) - error (0, retcode == -1 ? errno : 0, - "failed to commit dead revision for `%s'", finfo->fullname); - if (prev_rev != NULL) - free (prev_rev); - return 1; - } - /* At this point, the file has been committed as removed. We should - probably tell the history file about it */ - corev = rev ? RCS_getbranch (finfo->rcs, rev, 1) : RCS_head (finfo->rcs); - history_write ('R', NULL, corev, finfo->file, finfo->repository); - free (corev); - - if (rev != NULL) - free (rev); - - old_path = xstrdup (finfo->rcs->path); - if (!branch) - RCS_setattic (finfo->rcs, 1); - - /* Print message that file was removed. */ - cvs_output (old_path, 0); - cvs_output (" <-- ", 0); - cvs_output (finfo->file, 0); - cvs_output ("\nnew revision: delete; previous revision: ", 0); - cvs_output (prev_rev, 0); - cvs_output ("\ndone\n", 0); - free(prev_rev); - - free (old_path); - - Scratch_Entry (finfo->entries, finfo->file); - return 0; -} - - - -/* - * Do the actual checkin for added files - */ -static int -finaladd (finfo, rev, tag, options) - struct file_info *finfo; - char *rev; - char *tag; - char *options; -{ - int ret; - - ret = Checkin ('A', finfo, rev, tag, options, saved_message); - if (ret == 0) - { - char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM) - + sizeof (CVSEXT_LOG) + 10); - (void) sprintf (tmp, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG); - if (unlink_file (tmp) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", tmp); - free (tmp); - } - else if (finfo->rcs != NULL) - fixaddfile (finfo->rcs->path); - - (void) time (&last_register_time); - - return ret; -} - - - -/* - * Unlock an rcs file - */ -static void -unlockrcs (rcs) - RCSNode *rcs; -{ - int retcode; - - if ((retcode = RCS_unlock (rcs, NULL, 1)) != 0) - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not unlock %s", rcs->path); - else - RCS_rewrite (rcs, NULL, NULL); -} - - - -/* - * remove a partially added file. if we can parse it, leave it alone. - * - * FIXME: Every caller that calls this function can access finfo->rcs (the - * parsed RCSNode data), so we should be able to detect that the file needs - * to be removed without reparsing the file as we do below. - */ -static void -fixaddfile (rcs) - const char *rcs; -{ - RCSNode *rcsfile; - int save_really_quiet; - - save_really_quiet = really_quiet; - really_quiet = 1; - if ((rcsfile = RCS_parsercsfile (rcs)) == NULL) - { - if (unlink_file (rcs) < 0) - error (0, errno, "cannot remove %s", rcs); - } - else - freercsnode (&rcsfile); - really_quiet = save_really_quiet; -} - - - -/* - * put the branch back on an rcs file - */ -static void -fixbranch (rcs, branch) - RCSNode *rcs; - char *branch; -{ - int retcode; - - if (branch != NULL) - { - if ((retcode = RCS_setbranch (rcs, branch)) != 0) - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "cannot restore branch to %s for %s", branch, rcs->path); - RCS_rewrite (rcs, NULL, NULL); - } -} - - - -/* - * do the initial part of a file add for the named file. if adding - * with a tag, put the file in the Attic and point the symbolic tag - * at the committed revision. - * - * INPUTS - * file The name of the file in the workspace. - * repository The repository directory to expect to find FILE,v in. - * tag The name or rev num of the branch being added to, if any. - * options Any RCS keyword expansion options specified by the user. - * rcsnode A pointer to the pre-parsed RCSNode for this file, if the file - * exists in the repository. If this is NULL, assume the file - * does not yet exist. - * - * RETURNS - * 0 on success. - * 1 on errors, after printing any appropriate error messages. - * - * ERRORS - * This function will return an error when any of the following functions do: - * add_rcs_file - * RCS_setattic - * lock_RCS - * RCS_checkin - * RCS_parse (called to verify the newly created archive file) - * RCS_settag - */ - -static int -checkaddfile (file, repository, tag, options, rcsnode) - const char *file; - const char *repository; - const char *tag; - const char *options; - RCSNode **rcsnode; -{ - RCSNode *rcs; - char *fname; - int newfile = 0; /* Set to 1 if we created a new RCS archive. */ - int retval = 1; - int adding_on_branch; - - assert (rcsnode != NULL); - - /* Callers expect to be able to use either "" or NULL to mean the - default keyword expansion. */ - if (options != NULL && options[0] == '\0') - options = NULL; - if (options != NULL) - assert (options[0] == '-' && options[1] == 'k'); - - /* If numeric, it is on the trunk; check_fileproc enforced - this. */ - adding_on_branch = tag != NULL && !isdigit ((unsigned char) tag[0]); - - if (*rcsnode == NULL) - { - char *rcsname; - char *desc = NULL; - size_t descalloc = 0; - size_t desclen = 0; - const char *opt; - - if ( adding_on_branch ) - { - mode_t omask; - rcsname = xmalloc (strlen (repository) - + sizeof (CVSATTIC) - + strlen (file) - + sizeof (RCSEXT) - + 3); - (void) sprintf (rcsname, "%s/%s", repository, CVSATTIC); - omask = umask ( cvsumask ); - if (CVS_MKDIR (rcsname, 0777 ) != 0 && errno != EEXIST) - error (1, errno, "cannot make directory `%s'", rcsname); - (void) umask ( omask ); - (void) sprintf (rcsname, - "%s/%s/%s%s", - repository, - CVSATTIC, - file, - RCSEXT); - } - else - { - rcsname = xmalloc (strlen (repository) - + strlen (file) - + sizeof (RCSEXT) - + 2); - (void) sprintf (rcsname, - "%s/%s%s", - repository, - file, - RCSEXT); - } - - /* this is the first time we have ever seen this file; create - an RCS file. */ - fname = xmalloc (strlen (file) + sizeof (CVSADM) - + sizeof (CVSEXT_LOG) + 10); - (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG); - /* If the file does not exist, no big deal. In particular, the - server does not (yet at least) create CVSEXT_LOG files. */ - if (isfile (fname)) - /* FIXME: Should be including update_dir in the appropriate - place here. */ - get_file (fname, fname, "r", &desc, &descalloc, &desclen); - free (fname); - - /* From reading the RCS 5.7 source, "rcs -i" adds a newline to the - end of the log message if the message is nonempty. - Do it. RCS also deletes certain whitespace, in cleanlogmsg, - which we don't try to do here. */ - if (desclen > 0) - { - expand_string (&desc, &descalloc, desclen + 1); - desc[desclen++] = '\012'; - } - - /* Set RCS keyword expansion options. */ - if (options != NULL) - opt = options + 2; - else - opt = NULL; - - /* This message is an artifact of the time when this - was implemented via "rcs -i". It should be revised at - some point (does the "initial revision" in the message from - RCS_checkin indicate that this is a new file? Or does the - "RCS file" message serve some function?). */ - cvs_output ("RCS file: ", 0); - cvs_output (rcsname, 0); - cvs_output ("\ndone\n", 0); - - if (add_rcs_file (NULL, rcsname, file, NULL, opt, - NULL, NULL, 0, NULL, - desc, desclen, NULL) != 0) - { - if (rcsname != NULL) - free (rcsname); - goto out; - } - rcs = RCS_parsercsfile (rcsname); - newfile = 1; - if (rcsname != NULL) - free (rcsname); - if (desc != NULL) - free (desc); - *rcsnode = rcs; - } - else - { - /* file has existed in the past. Prepare to resurrect. */ - char *rev; - char *oldexpand; - - rcs = *rcsnode; - - oldexpand = RCS_getexpand (rcs); - if ((oldexpand != NULL - && options != NULL - && strcmp (options + 2, oldexpand) != 0) - || (oldexpand == NULL && options != NULL)) - { - /* We tell the user about this, because it means that the - old revisions will no longer retrieve the way that they - used to. */ - error (0, 0, "changing keyword expansion mode to %s", options); - RCS_setexpand (rcs, options + 2); - } - - if (!adding_on_branch) - { - /* We are adding on the trunk, so move the file out of the - Attic. */ - if (!(rcs->flags & INATTIC)) - { - error (0, 0, "warning: expected %s to be in Attic", - rcs->path); - } - - /* 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 (rcs, 0)) - { - goto out; - } - } - - rev = RCS_getversion (rcs, tag, NULL, 1, (int *) NULL); - /* and lock it */ - if (lock_RCS (file, rcs, rev, repository)) - { - error (0, 0, "cannot lock revision %s in `%s'.", - rev ? rev : tag ? tag : "HEAD", rcs->path); - if (rev != NULL) - free (rev); - goto out; - } - - if (rev != NULL) - free (rev); - } - - /* 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) - { - if (newfile) - { - char *tmp; - FILE *fp; - int retcode; - - /* 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 (rcs, NULL, tmp, NULL, 0, - 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->path); - free (fname); - 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 (&rcs); - rcs = RCS_parse (file, repository); - if (rcs == NULL) - { - error (0, 0, "could not read %s in %s", file, repository); - goto out; - } - *rcsnode = rcs; - - /* and lock it once again. */ - if (lock_RCS (file, rcs, NULL, repository)) - { - error (0, 0, "cannot lock initial revision in `%s'.", - rcs->path); - goto out; - } - } - - /* when adding with a tag, we need to stub a branch, if it - doesn't already exist. */ - if (!RCS_nodeisbranch (rcs, tag)) - { - /* branch does not exist. Stub it. */ - char *head; - char *magicrev; - int retcode; - time_t headtime = -1; - char *revnum, *tmp; - FILE *fp; - time_t t = -1; - struct tm *ct; - - fixbranch (rcs, sbranch); - - head = RCS_getversion (rcs, NULL, NULL, 0, (int *) NULL); - if (!head) - error (1, 0, "No head revision in archive file `%s'.", - rcs->path); - magicrev = RCS_magicrev (rcs, head); - - /* If this is not a new branch, then we will want a dead - version created before this one. */ - if (!newfile) - headtime = RCS_getrevtime (rcs, head, 0, 0); - - retcode = RCS_settag (rcs, tag, magicrev); - RCS_rewrite (rcs, NULL, NULL); - - free (head); - free (magicrev); - - if (retcode != 0) - { - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not stub branch %s for %s", tag, rcs->path); - goto out; - } - /* We need to add a dead version here to avoid -rtag -Dtime - checkout problems between when the head version was - created and now. */ - if (!newfile && headtime != -1) - { - /* 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); - - /* As we will be hacking the delta date, put the time - this was added into the log message. */ - t = time(NULL); - ct = gmtime(&t); - tmp = xmalloc (strlen (file) + strlen (tag) + 80); - - (void) sprintf (tmp, - "file %s was added on branch %s on %d-%02d-%02d %02d:%02d:%02d +0000", - file, tag, - ct->tm_year + (ct->tm_year < 100 ? 0 : 1900), - ct->tm_mon + 1, ct->tm_mday, - ct->tm_hour, ct->tm_min, ct->tm_sec); - - /* commit a dead revision. */ - revnum = RCS_whatbranch (rcs, tag); - retcode = RCS_checkin (rcs, NULL, tmp, revnum, headtime, - RCS_FLAGS_DEAD | - RCS_FLAGS_QUIET | - RCS_FLAGS_USETIME); - free (revnum); - free (tmp); - - if (retcode != 0) - { - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not created dead stub %s for %s", tag, - rcs->path); - 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 (&rcs); - rcs = RCS_parse (file, repository); - if (rcs == NULL) - { - error (0, 0, "could not read %s", rcs->path); - goto out; - } - *rcsnode = rcs; - } - } - else - { - /* lock the branch. (stubbed branches need not be locked.) */ - if (lock_RCS (file, rcs, NULL, repository)) - { - error (0, 0, "cannot lock head revision in `%s'.", rcs->path); - goto out; - } - } - - if (*rcsnode != rcs) - { - freercsnode(rcsnode); - *rcsnode = rcs; - } - } - - fileattr_newfile (file); - - /* At this point, we used to set the file mode of the RCS file - based on the mode of the file in the working directory. If we - are creating the RCS file for the first time, add_rcs_file does - this already. If we are re-adding the file, then perhaps it is - consistent to preserve the old file mode, just as we preserve - the old keyword expansion mode. - - If we decide that we should change the modes, then we can't do - it here anyhow. At this point, the RCS file may be owned by - somebody else, so a chmod will fail. We need to instead do the - chmod after rewriting it. - - FIXME: In general, I think the file mode (and the keyword - expansion mode) should be associated with a particular revision - of the file, so that it is possible to have different revisions - of a file have different modes. */ - - retval = 0; - - out: - if (retval != 0 && SIG_inCrSect ()) - SIG_endCrSect (); - return retval; -} - - - -/* - * Attempt to place a lock on the RCS file; returns 0 if it could and 1 if it - * couldn't. If the RCS file currently has a branch as the head, we must - * move the head back to the trunk before locking the file, and be sure to - * put the branch back as the head if there are any errors. - */ -static int -lock_RCS (user, rcs, rev, repository) - const char *user; - RCSNode *rcs; - const char *rev; - const char *repository; -{ - char *branch = NULL; - int err = 0; - - /* - * For a specified, numeric revision of the form "1" or "1.1", (or when - * no revision is specified ""), definitely move the branch to the trunk - * before locking the RCS file. - * - * The assumption is that if there is more than one revision on the trunk, - * the head points to the trunk, not a branch... and as such, it's not - * necessary to move the head in this case. - */ - if (rev == NULL - || (rev && isdigit ((unsigned char) *rev) && numdots (rev) < 2)) - { - branch = xstrdup (rcs->branch); - if (branch != NULL) - { - if (RCS_setbranch (rcs, NULL) != 0) - { - error (0, 0, "cannot change branch to default for %s", - rcs->path); - if (branch) - free (branch); - return 1; - } - } - err = RCS_lock (rcs, NULL, 1); - } - else - { - RCS_lock (rcs, rev, 1); - } - - /* We used to call RCS_rewrite here, and that might seem - appropriate in order to write out the locked revision - information. However, such a call would actually serve no - purpose. CVS locks will prevent any interference from other - CVS processes. The comment above rcs_internal_lockfile - explains that it is already unsafe to use RCS and CVS - simultaneously. It follows that writing out the locked - revision information here would add no additional security. - - If we ever do care about it, the proper fix is to create the - RCS lock file before calling this function, and maintain it - until the checkin is complete. - - The call to RCS_lock is still required at present, since in - some cases RCS_checkin will determine which revision to check - in by looking for a lock. FIXME: This is rather roundabout, - and a more straightforward approach would probably be easier to - understand. */ - - if (err == 0) - { - if (sbranch != NULL) - free (sbranch); - sbranch = branch; - return 0; - } - - /* try to restore the branch if we can on error */ - if (branch != NULL) - fixbranch (rcs, branch); - - if (branch) - free (branch); - return 1; -} - - - -/* - * free an UPDATE node's data - */ -void -update_delproc (p) - Node *p; -{ - struct logfile_info *li = p->data; - - if (li->tag) - free (li->tag); - if (li->rev_old) - free (li->rev_old); - if (li->rev_new) - free (li->rev_new); - free (li); -} - -/* - * Free the commit_info structure in p. - */ -static void -ci_delproc (p) - Node *p; -{ - struct commit_info *ci = p->data; - - if (ci->rev) - free (ci->rev); - if (ci->tag) - free (ci->tag); - if (ci->options) - free (ci->options); - free (ci); -} - -/* - * Free the commit_info structure in p. - */ -static void -masterlist_delproc (p) - Node *p; -{ - struct master_lists *ml = p->data; - - dellist (&ml->ulist); - dellist (&ml->cilist); - free (ml); -} diff --git a/contrib/cvs/src/create_adm.c b/contrib/cvs/src/create_adm.c deleted file mode 100644 index ccf744f..0000000 --- a/contrib/cvs/src/create_adm.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Create Administration. - * - * Creates a CVS administration directory based on the argument repository; the - * "Entries" file is prefilled from the "initrecord" argument. - */ - -#include "cvs.h" - -/* update_dir includes dir as its last component. - - Return value is 0 for success, or 1 if we printed a warning message. - Note that many errors are still fatal; particularly for unlikely errors - a fatal error is probably better than a warning which might be missed - or after which CVS might do something non-useful. If WARN is zero, then - don't print warnings; all errors are fatal then. */ - -int -Create_Admin (dir, update_dir, repository, tag, date, nonbranch, warn, - dotemplate) - const char *dir; - const char *update_dir; - const char *repository; - const char *tag; - const char *date; - int nonbranch; - int warn; - int dotemplate; -{ - FILE *fout; - char *cp; - char *reposcopy; - char *tmp; - - if (trace) - { - fprintf (stderr, "%s-> Create_Admin (%s, %s, %s, %s, %s, %d, %d, %d)\n", - CLIENT_SERVER_STR, - dir, update_dir, repository, tag ? tag : "", - date ? date : "", nonbranch, warn, dotemplate); - } - - if (noexec) - return 0; - - tmp = xmalloc (strlen (dir) + 100); - (void) sprintf (tmp, "%s/%s", dir, CVSADM); - if (isfile (tmp)) - error (1, 0, "there is a version in %s already", update_dir); - - if (CVS_MKDIR (tmp, 0777) < 0) - { - /* We want to print out the entire update_dir, since a lot of - our code calls this function with dir == "." or dir == - NULL. I hope that gives enough information in cases like - absolute pathnames; printing out xgetwd or something would - be way too verbose in the common cases. */ - - if (warn) - { - /* The reason that this is a warning, rather than silently - just skipping creating the directory, is that we don't want - CVS's behavior to vary subtly based on factors (like directory - permissions) which are not made clear to the user. With - the warning at least we let them know what is going on. */ - error (0, errno, "warning: cannot make directory %s in %s", - CVSADM, update_dir); - free (tmp); - return 1; - } - else - error (1, errno, "cannot make directory %s in %s", - CVSADM, update_dir); - } - - /* record the current cvs root for later use */ - - Create_Root (dir, current_parsed_root->original); - if (dir != NULL) - (void) sprintf (tmp, "%s/%s", dir, CVSADM_REP); - else - (void) strcpy (tmp, CVSADM_REP); - fout = CVS_FOPEN (tmp, "w+"); - if (fout == NULL) - { - if (update_dir[0] == '\0') - error (1, errno, "cannot open %s", tmp); - else - error (1, errno, "cannot open %s/%s", update_dir, CVSADM_REP); - } - reposcopy = xstrdup (repository); - Sanitize_Repository_Name (reposcopy); - - /* The top level of the repository is a special case -- we need to - write it with an extra dot at the end. This trailing `.' stuff - rubs me the wrong way -- on the other hand, I don't want to - spend the time making sure all of the code can handle it if we - don't do it. */ - - if (strcmp (reposcopy, current_parsed_root->directory) == 0) - { - reposcopy = xrealloc (reposcopy, strlen (reposcopy) + 3); - strcat (reposcopy, "/."); - } - - cp = reposcopy; - - /* - * If the Repository file is to hold a relative path, try to strip off - * the leading CVSroot argument. - */ - { - char *path = xmalloc (strlen (current_parsed_root->directory) + 2); - - (void) sprintf (path, "%s/", current_parsed_root->directory); - if (strncmp (cp, path, strlen (path)) == 0) - cp += strlen (path); - free (path); - } - - if (fprintf (fout, "%s\n", cp) < 0) - { - if (update_dir[0] == '\0') - error (1, errno, "write to %s failed", tmp); - else - error (1, errno, "write to %s/%s failed", update_dir, CVSADM_REP); - } - if (fclose (fout) == EOF) - { - if (update_dir[0] == '\0') - error (1, errno, "cannot close %s", tmp); - else - error (1, errno, "cannot close %s/%s", update_dir, CVSADM_REP); - } - - /* now, do the Entries file */ - if (dir != NULL) - (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT); - else - (void) strcpy (tmp, CVSADM_ENT); - fout = CVS_FOPEN (tmp, "w+"); - if (fout == NULL) - { - if (update_dir[0] == '\0') - error (1, errno, "cannot open %s", tmp); - else - error (1, errno, "cannot open %s/%s", update_dir, CVSADM_ENT); - } - if (fclose (fout) == EOF) - { - if (update_dir[0] == '\0') - error (1, errno, "cannot close %s", tmp); - else - error (1, errno, "cannot close %s/%s", update_dir, CVSADM_ENT); - } - - /* Create a new CVS/Tag file */ - WriteTag (dir, tag, date, nonbranch, update_dir, repository); - -#ifdef SERVER_SUPPORT - if (server_active && dotemplate) - { - server_template (update_dir, repository); - } - - if (trace) - { - fprintf (stderr, "%c<- Create_Admin\n", - (server_active) ? 'S' : ' '); - } -#endif - - free (reposcopy); - free (tmp); - return 0; -} diff --git a/contrib/cvs/src/cvs.h b/contrib/cvs/src/cvs.h deleted file mode 100644 index 4b7d9f5..0000000 --- a/contrib/cvs/src/cvs.h +++ /dev/null @@ -1,945 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS kit. - */ - -/* - * basic information used in all source files - * - * $FreeBSD$ - */ - - -#ifdef HAVE_CONFIG_H -# include <config.h> /* this is stuff found via autoconf */ -#endif /* CONFIG_H */ - -/* Changed from if __STDC__ to ifdef __STDC__ because of Sun's acc compiler */ - -#ifdef __STDC__ -#define PTR void * -#else -#define PTR char * -#endif - -/* Add prototype support. */ -#ifndef PROTO -#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) -#define PROTO(ARGS) ARGS -#else -#define PROTO(ARGS) () -#endif -#endif - -#include <stdio.h> - -/* Under OS/2, <stdio.h> doesn't define popen()/pclose(). */ -#ifdef USE_OWN_POPEN -#include "popen.h" -#endif - -/* Begin GNULIB headers. */ -#include "xsize.h" -/* End GNULIB headers. */ - -#ifdef STDC_HEADERS -#include <stdlib.h> -#else -extern void exit (); -extern char *getenv(); -#endif - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#ifdef HAVE_STRING_H -#include <string.h> -#else -#include <strings.h> -#endif - -#ifdef SERVER_SUPPORT -/* If the system doesn't provide strerror, it won't be declared in - string.h. */ -char *strerror (); -#endif - -#ifdef HAVE_FNMATCH -# include <fnmatch.h> /* This is supposed to be available on Posix systems */ -#else /* HAVE_FNMATCH */ -# include "fnmatch.h" /* Our substitute */ -#endif /* HAVE_FNMATCH */ - -#include <ctype.h> -#include <pwd.h> -#include <signal.h> - -#ifdef HAVE_ERRNO_H -#include <errno.h> -#else -#ifndef errno -extern int errno; -#endif /* !errno */ -#endif /* HAVE_ERRNO_H */ - -#include "system.h" - -#include "hash.h" -#include "stack.h" - -#include "root.h" - -#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) -# include "client.h" -#endif - -#ifdef MY_NDBM -#include "myndbm.h" -#else -#include <ndbm.h> -#endif /* MY_NDBM */ - -#include "regex.h" -#include "getopt.h" -#include "wait.h" - -#include "rcs.h" - - -/* This actually gets set in system.h. Note that the _ONLY_ reason for - this is if various system calls (getwd, getcwd, readlink) require/want - us to use it. All other parts of CVS allocate pathname buffers - dynamically, and we want to keep it that way. */ -#ifndef PATH_MAX -#ifdef MAXPATHLEN -#define PATH_MAX MAXPATHLEN+2 -#else -#define PATH_MAX 1024+2 -#endif -#endif /* PATH_MAX */ - -/* Definitions for the CVS Administrative directory and the files it contains. - Here as #define's to make changing the names a simple task. */ - -#ifdef USE_VMS_FILENAMES -#define CVSADM "CVS" -#define CVSADM_ENT "CVS/Entries." -#define CVSADM_ENTBAK "CVS/Entries.Backup" -#define CVSADM_ENTLOG "CVS/Entries.Log" -#define CVSADM_ENTSTAT "CVS/Entries.Static" -#define CVSADM_REP "CVS/Repository." -#define CVSADM_ROOT "CVS/Root." -#define CVSADM_TAG "CVS/Tag." -#define CVSADM_NOTIFY "CVS/Notify." -#define CVSADM_NOTIFYTMP "CVS/Notify.tmp" -#define CVSADM_BASE "CVS/Base" -#define CVSADM_BASEREV "CVS/Baserev." -#define CVSADM_BASEREVTMP "CVS/Baserev.tmp" -#define CVSADM_TEMPLATE "CVS/Template." -#else /* USE_VMS_FILENAMES */ -#define CVSADM "CVS" -#define CVSADM_ENT "CVS/Entries" -#define CVSADM_ENTBAK "CVS/Entries.Backup" -#define CVSADM_ENTLOG "CVS/Entries.Log" -#define CVSADM_ENTSTAT "CVS/Entries.Static" -#define CVSADM_REP "CVS/Repository" -#define CVSADM_ROOT "CVS/Root" -#define CVSADM_TAG "CVS/Tag" -#define CVSADM_NOTIFY "CVS/Notify" -#define CVSADM_NOTIFYTMP "CVS/Notify.tmp" -/* A directory in which we store base versions of files we currently are - editing with "cvs edit". */ -#define CVSADM_BASE "CVS/Base" -#define CVSADM_BASEREV "CVS/Baserev" -#define CVSADM_BASEREVTMP "CVS/Baserev.tmp" -/* File which contains the template for use in log messages. */ -#define CVSADM_TEMPLATE "CVS/Template" -#endif /* USE_VMS_FILENAMES */ - -/* This is the special directory which we use to store various extra - per-directory information in the repository. It must be the same as - CVSADM to avoid creating a new reserved directory name which users cannot - use, but is a separate #define because if anyone changes it (which I don't - recommend), one needs to deal with old, unconverted, repositories. - - See fileattr.h for details about file attributes, the only thing stored - in CVSREP currently. */ -#define CVSREP "CVS" - -/* - * Definitions for the CVSROOT Administrative directory and the files it - * contains. This directory is created as a sub-directory of the $CVSROOT - * environment variable, and holds global administration information for the - * entire source repository beginning at $CVSROOT. - */ -#define CVSROOTADM "CVSROOT" -#define CVSROOTADM_MODULES "modules" -#define CVSROOTADM_LOGINFO "loginfo" -#define CVSROOTADM_RCSINFO "rcsinfo" -#define CVSROOTADM_COMMITINFO "commitinfo" -#define CVSROOTADM_TAGINFO "taginfo" -#define CVSROOTADM_EDITINFO "editinfo" -#define CVSROOTADM_VERIFYMSG "verifymsg" -#define CVSROOTADM_HISTORY "history" -#define CVSROOTADM_VALTAGS "val-tags" -#define CVSROOTADM_IGNORE "cvsignore" -#define CVSROOTADM_CHECKOUTLIST "checkoutlist" -#define CVSROOTADM_WRAPPER "cvswrappers" -#define CVSROOTADM_NOTIFY "notify" -#define CVSROOTADM_USERS "users" -#define CVSROOTADM_READERS "readers" -#define CVSROOTADM_WRITERS "writers" -#define CVSROOTADM_PASSWD "passwd" -#define CVSROOTADM_CONFIG "config" -#define CVSROOTADM_OPTIONS "options" - -#define CVSNULLREPOS "Emptydir" /* an empty directory */ - -/* Other CVS file names */ - -/* Files go in the attic if the head main branch revision is dead, - otherwise they go in the regular repository directories. The whole - concept of having an attic is sort of a relic from before death - support but on the other hand, it probably does help the speed of - some operations (such as main branch checkouts and updates). */ -#define CVSATTIC "Attic" - -#define CVSLCK "#cvs.lock" -#define CVSHISTORYLCK "#cvs.history.lock" -#define CVSVALTAGSLCK "#cvs.val-tags.lock" -#define CVSRFL "#cvs.rfl" -#define CVSWFL "#cvs.wfl" -#define CVSRFLPAT "#cvs.rfl.*" /* wildcard expr to match read locks */ -#define CVSEXT_LOG ",t" -#define CVSPREFIX ",," -#define CVSDOTIGNORE ".cvsignore" -#define CVSDOTWRAPPER ".cvswrappers" - -/* Command attributes -- see function lookup_command_attribute(). */ -#define CVS_CMD_IGNORE_ADMROOT 1 - -/* Set if CVS needs to create a CVS/Root file upon completion of this - command. The name may be slightly confusing, because the flag - isn't really as general purpose as it seems (it is not set for cvs - release). */ - -#define CVS_CMD_USES_WORK_DIR 2 - -#define CVS_CMD_MODIFIES_REPOSITORY 4 - -/* miscellaneous CVS defines */ - -/* This is the string which is at the start of the non-log-message lines - that we put up for the user when they edit the log message. */ -#define CVSEDITPREFIX "CVS: " -/* Number of characters in CVSEDITPREFIX to compare when deciding to strip - off those lines. We don't check for the space, to accomodate users who - have editors which strip trailing spaces. */ -#define CVSEDITPREFIXLEN 4 - -#define CVSLCKAGE (60*60) /* 1-hour old lock files cleaned up */ -#define CVSLCKSLEEP 30 /* wait 30 seconds before retrying */ -#define CVSBRANCH "1.1.1" /* RCS branch used for vendor srcs */ - -#ifdef USE_VMS_FILENAMES -#define BAKPREFIX "_$" -#define DEVNULL "NLA0:" -#else /* USE_VMS_FILENAMES */ -#define BAKPREFIX ".#" /* when rcsmerge'ing */ -#ifndef DEVNULL -#define DEVNULL "/dev/null" -#endif -#endif /* USE_VMS_FILENAMES */ - -/* - * Special tags. -rHEAD refers to the head of an RCS file, regardless of any - * sticky tags. -rBASE refers to the current revision the user has checked - * out This mimics the behaviour of RCS. - */ -#define TAG_HEAD "HEAD" -#define TAG_BASE "BASE" - -/* Environment variable used by CVS */ -#define CVSREAD_ENV "CVSREAD" /* make files read-only */ -#define CVSREAD_DFLT 0 /* writable files by default */ - -#define CVSREADONLYFS_ENV "CVSREADONLYFS" /* repository is read-only */ - -#define TMPDIR_ENV "TMPDIR" /* Temporary directory */ - -#define EDITOR1_ENV "CVSEDITOR" /* which editor to use */ -#define EDITOR2_ENV "VISUAL" /* which editor to use */ -#define EDITOR3_ENV "EDITOR" /* which editor to use */ - -#define CVSROOT_ENV "CVSROOT" /* source directory root */ -/* Define CVSROOT_DFLT to a fallback value for CVSROOT. - * -#undef CVSROOT_DFL - */ - -#define IGNORE_ENV "CVSIGNORE" /* More files to ignore */ -#define WRAPPER_ENV "CVSWRAPPERS" /* name of the wrapper file */ - -#define CVSUMASK_ENV "CVSUMASK" /* Effective umask for repository */ - -/* - * If the beginning of the Repository matches the following string, strip it - * so that the output to the logfile does not contain a full pathname. - * - * If the CVSROOT environment variable is set, it overrides this define. - */ -#define REPOS_STRIP "/master/" - -/* Large enough to hold DATEFORM. Not an arbitrary limit as long as - it is used for that purpose, and not to hold a string from the - command line, the client, etc. */ -#define MAXDATELEN 50 - -/* The type of an entnode. */ -enum ent_type -{ - ENT_FILE, ENT_SUBDIR -}; - -/* structure of a entry record */ -struct entnode -{ - enum ent_type type; - char *user; - char *version; - - /* Timestamp, or "" if none (never NULL). */ - char *timestamp; - - /* Keyword expansion options, or "" if none (never NULL). */ - char *options; - - char *tag; - char *date; - char *conflict; -}; -typedef struct entnode Entnode; - -/* The type of request that is being done in do_module() */ -enum mtype -{ - CHECKOUT, TAG, PATCH, EXPORT, MISC -}; - -/* - * structure used for list-private storage by Entries_Open() and - * Version_TS() and Find_Directories(). - */ -struct stickydirtag -{ - /* These fields pass sticky tag information from Entries_Open() to - Version_TS(). */ - int aflag; - char *tag; - char *date; - int nonbranch; - - /* This field is set by Entries_Open() if there was subdirectory - information; Find_Directories() uses it to see whether it needs - to scan the directory itself. */ - int subdirs; -}; - -/* Flags for find_{names,dirs} routines */ -#define W_LOCAL 0x01 /* look for files locally */ -#define W_REPOS 0x02 /* look for files in the repository */ -#define W_ATTIC 0x04 /* look for files in the attic */ - -/* Flags for return values of direnter procs for the recursion processor */ -enum direnter_type -{ - R_PROCESS = 1, /* process files and maybe dirs */ - R_SKIP_FILES, /* don't process files in this dir */ - R_SKIP_DIRS, /* don't process sub-dirs */ - R_SKIP_ALL /* don't process files or dirs */ -}; -#ifdef ENUMS_CAN_BE_TROUBLE -typedef int Dtype; -#else -typedef enum direnter_type Dtype; -#endif - -/* Recursion processor lock types */ -#define CVS_LOCK_NONE 0 -#define CVS_LOCK_READ 1 -#define CVS_LOCK_WRITE 2 - -extern const char *program_name, *program_path, *cvs_cmd_name; -extern char *Tmpdir, *Editor; -extern int cvsadmin_root; -extern char *CurDir; -extern int really_quiet, quiet; -extern int use_editor; -extern int cvswrite; -extern mode_t cvsumask; -extern char *RCS_citag; - - - -/* This global variable holds the global -d option. It is NULL if -d - was not used, which means that we must get the CVSroot information - from the CVSROOT environment variable or from a CVS/Root file. */ -extern char *CVSroot_cmdline; - -/* These variables keep track of all of the CVSROOT directories that - have been seen by the client and the current one of those selected. */ -extern List *root_directories; -extern cvsroot_t *current_parsed_root; - -extern char *emptydir_name PROTO ((void)); -extern int safe_location PROTO ((char *)); - -extern int trace; /* Show all commands */ -extern int noexec; /* Don't modify disk anywhere */ -extern int readonlyfs; /* fail on all write locks; succeed all read locks */ -extern int logoff; /* Don't write history entry */ -extern int require_real_user; /* skip CVSROOT/passwd, /etc/passwd users only*/ - -extern int top_level_admin; - - -#define LOGMSG_REREAD_NEVER 0 /* do_verify - never reread message */ -#define LOGMSG_REREAD_ALWAYS 1 /* do_verify - always reread message */ -#define LOGMSG_REREAD_STAT 2 /* do_verify - reread message if changed */ -extern int RereadLogAfterVerify; - -#ifdef CLIENT_SUPPORT -extern List *dirs_sent_to_server; /* used to decide which "Argument - xxx" commands to send to each - server in multiroot mode. */ -#endif - -extern char hostname[]; - -/* Externs that are included directly in the CVS sources */ - -int RCS_merge PROTO((RCSNode *, const char *, const char *, const char *, - const char *, const char *)); -/* Flags used by RCS_* functions. See the description of the individual - functions for which flags mean what for each function. */ -#define RCS_FLAGS_FORCE 1 -#define RCS_FLAGS_DEAD 2 -#define RCS_FLAGS_QUIET 4 -#define RCS_FLAGS_MODTIME 8 -#define RCS_FLAGS_KEEPFILE 16 -#define RCS_FLAGS_USETIME 32 - -extern int RCS_exec_rcsdiff PROTO ((RCSNode *rcsfile, int diff_argc, - char *const *diff_argv, - const char *options, - const char *rev1, const char *rev1_cache, - const char *rev2, const char *label1, - const char *label2, const char *workfile)); -extern int diff_exec PROTO ((const char *file1, const char *file2, - const char *label1, const char *label2, - int diff_argc, char *const *diff_argv, - const char *out)); - - -#include "error.h" - -DBM *open_module PROTO((void)); -FILE *open_file PROTO((const char *, const char *)); -List *Find_Directories PROTO((char *repository, int which, List *entries)); -void Entries_Close PROTO((List *entries)); -List *Entries_Open PROTO ((int aflag, char *update_dir)); -void Subdirs_Known PROTO((List *entries)); -void Subdir_Register PROTO((List *, const char *, const char *)); -void Subdir_Deregister PROTO((List *, const char *, const char *)); - -char *Make_Date PROTO((char *rawdate)); -char *date_from_time_t PROTO ((time_t)); -void date_to_internet PROTO ((char *, const char *)); -void date_to_tm PROTO ((struct tm *, const char *)); -void tm_to_internet PROTO ((char *, const struct tm *)); - -char *Name_Repository PROTO((const char *dir, const char *update_dir)); -const char *Short_Repository PROTO((const char *repository)); -void Sanitize_Repository_Name PROTO((char *repository)); - -char *previous_rev PROTO ((RCSNode *rcs, const char *rev)); -char *gca PROTO ((const char *rev1, const char *rev2)); -extern void check_numeric PROTO ((const char *, int, char **)); -char *getcaller PROTO ((void)); -char *time_stamp PROTO ((const char *file)); - -void *xmalloc PROTO((size_t bytes)); -void *xrealloc PROTO((void *ptr, size_t bytes)); -void expand_string PROTO ((char **, size_t *, size_t)); -void xrealloc_and_strcat PROTO ((char **, size_t *, const char *)); -char *xstrdup PROTO((const char *str)); -int strip_trailing_newlines PROTO((char *str)); -int pathname_levels PROTO ((const char *path)); - -typedef int (*CALLPROC) PROTO((const char *repository, const char *value)); -int Parse_Info PROTO((const char *infofile, const char *repository, - CALLPROC callproc, int all)); -extern int parse_config PROTO ((char *)); - -typedef RETSIGTYPE (*SIGCLEANUPPROC) PROTO(()); -int SIG_register PROTO((int sig, SIGCLEANUPPROC sigcleanup)); -int isdir PROTO((const char *file)); -int isfile PROTO((const char *file)); -int islink PROTO((const char *file)); -int isdevice PROTO ((const char *)); -int isreadable PROTO((const char *file)); -int iswritable PROTO((const char *file)); -int isaccessible PROTO((const char *file, const int mode)); -int isabsolute PROTO((const char *filename)); -#ifdef HAVE_READLINK -char *xreadlink PROTO((const char *link)); -#endif -char *xresolvepath PROTO((const char *path)); -const char *last_component PROTO((const char *path)); -char *get_homedir PROTO ((void)); -char *strcat_filename_onto_homedir PROTO ((const char *, const char *)); -char *cvs_temp_name PROTO ((void)); -FILE *cvs_temp_file PROTO ((char **filename)); -void parseopts PROTO ((const char *root)); - -int numdots PROTO((const char *s)); -char *increment_revnum PROTO ((const char *)); -int compare_revnums PROTO ((const char *, const char *)); -int unlink_file PROTO((const char *f)); -int unlink_file_dir PROTO((const char *f)); - - - -/* This is the structure that the recursion processor passes to the - fileproc to tell it about a particular file. */ -struct file_info -{ - /* Name of the file, without any directory component. */ - const char *file; - - /* Name of the directory we are in, relative to the directory in - which this command was issued. We have cd'd to this directory - (either in the working directory or in the repository, depending - on which sort of recursion we are doing). If we are in the directory - in which the command was issued, this is "". */ - const char *update_dir; - - /* update_dir and file put together, with a slash between them as - necessary. This is the proper way to refer to the file in user - messages. */ - const char *fullname; - - /* Name of the directory corresponding to the repository which contains - this file. */ - const char *repository; - - /* The pre-parsed entries for this directory. */ - List *entries; - - RCSNode *rcs; -}; - - - -int update PROTO((int argc, char *argv[])); -/* The only place this is currently used outside of update.c is add.c. - * Restricting its use to update.c seems to be in the best interest of - * modularity, but I can't think of a good way to get an update of a - * resurrected file done and print the fact otherwise. - */ -void write_letter PROTO ((struct file_info *finfo, int letter)); -int xcmp PROTO((const char *file1, const char *file2)); -int yesno PROTO((void)); -void *valloc PROTO((size_t bytes)); -time_t get_date PROTO((char *date, struct timeb *now)); -extern int Create_Admin PROTO ((const char *dir, const char *update_dir, - const char *repository, const char *tag, - const char *date, - int nonbranch, int warn, int dotemplate)); -extern int expand_at_signs PROTO ((const char *, off_t, FILE *)); - -/* Locking subsystem (implemented in lock.c). */ - -int Reader_Lock PROTO((char *xrepository)); -void Lock_Cleanup PROTO((void)); - -/* Writelock an entire subtree, well the part specified by ARGC, ARGV, LOCAL, - and AFLAG, anyway. */ -void lock_tree_for_write PROTO ((int argc, char **argv, int local, int which, - int aflag)); - -/* See lock.c for description. */ -extern void lock_dir_for_write PROTO ((char *)); - -/* Get a write lock for the history file. */ -int history_lock PROTO ((const char *)); -void clear_history_lock PROTO ((void)); - -/* Get a write lock for the val-tags file. */ -int val_tags_lock PROTO ((const char *)); -void clear_val_tags_lock PROTO ((void)); - -/* LockDir setting from CVSROOT/config. */ -extern char *lock_dir; - -void Scratch_Entry PROTO((List * list, const char *fname)); -void ParseTag PROTO((char **tagp, char **datep, int *nonbranchp)); -void WriteTag PROTO ((const char *dir, const char *tag, const char *date, - int nonbranch, const char *update_dir, - const char *repository)); -void WriteTemplate PROTO ((const char *dir, const char *update_dir)); -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 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)); -void ign_add PROTO((char *ign, int hold)); -void ign_add_file PROTO((char *file, int hold)); -void ign_setup PROTO((void)); -void ign_dir_add PROTO((char *name)); -int ignore_directory PROTO((const char *name)); -typedef void (*Ignore_proc) PROTO ((const char *, const char *)); -extern void ignore_files PROTO ((List *, List *, const char *, Ignore_proc)); -extern int ign_inhibit_server; - -#include "update.h" - -void line2argv PROTO ((int *pargc, char ***argv, char *line, char *sepchars)); -void make_directories PROTO((const char *name)); -void make_directory PROTO((const char *name)); -extern int mkdir_if_needed PROTO ((const char *name)); -void rename_file PROTO((const char *from, const char *to)); -/* 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 - former in the future (e.g. "cvs status *.h" including files which don't exist - in the working directory). The result is placed in *PARGC and *PARGV; - the *PARGV array itself and all the strings it contains are newly - malloc'd. It is OK to call it with PARGC == &ARGC or PARGV == &ARGV. */ -extern void expand_wild PROTO ((int argc, char **argv, - int *pargc, char ***pargv)); - -#ifdef SERVER_SUPPORT -extern int cvs_casecmp PROTO ((const char *, const char *)); -#endif - -void strip_trailing_slashes PROTO((char *path)); -void update_delproc PROTO((Node * p)); -void usage PROTO((const char *const *cpp)); -void xchmod PROTO((const char *fname, int writable)); -char *xgetwd PROTO((void)); -List *Find_Names PROTO((char *repository, int which, int aflag, - List **optentries)); -void Register PROTO((List * list, const char *fname, const char *vn, - const char *ts, const char *options, const char *tag, - const char *date, const char *ts_conflict)); -void Update_Logfile PROTO((const char *repository, const char *xmessage, - FILE * xlogfp, List * xchanges)); -void do_editor PROTO((const char *dir, char **messagep, - const char *repository, List * changes)); - -void do_verify PROTO((char **messagep, const char *repository)); - -typedef int (*CALLBACKPROC) PROTO((int argc, char *argv[], char *where, - char *mwhere, char *mfile, int shorten, int local_specified, - char *omodule, char *msg)); - -typedef int (*FILEPROC) PROTO ((void *callerdat, struct file_info *finfo)); -typedef int (*FILESDONEPROC) PROTO ((void *callerdat, int err, - const char *repository, - const char *update_dir, - List *entries)); -typedef Dtype (*DIRENTPROC) PROTO ((void *callerdat, const char *dir, - const char *repos, const char *update_dir, - List *entries)); -typedef int (*DIRLEAVEPROC) PROTO ((void *callerdat, const char *dir, int err, - const char *update_dir, List *entries)); - -extern int mkmodules PROTO ((char *dir)); -extern int init PROTO ((int argc, char **argv)); - -int do_module PROTO((DBM * db, char *mname, enum mtype m_type, char *msg, - CALLBACKPROC callback_proc, char *where, int shorten, - int local_specified, int run_module_prog, int build_dirs, - char *extra_arg)); -void history_write PROTO((int type, const char *update_dir, const char *revs, - const char *name, const char *repository)); -int start_recursion PROTO((FILEPROC fileproc, FILESDONEPROC filesdoneproc, - DIRENTPROC direntproc, DIRLEAVEPROC dirleaveproc, - void *callerdat, - int argc, char *argv[], int local, int which, - int aflag, int locktype, char *update_preload, - int dosrcs, char *repository)); -void SIG_beginCrSect PROTO((void)); -void SIG_endCrSect PROTO((void)); -int SIG_inCrSect PROTO((void)); -void read_cvsrc PROTO((int *argc, char ***argv, const char *cmdname)); - -char *make_message_rcslegal PROTO((const char *message)); -extern int file_has_markers PROTO ((const struct file_info *)); -extern void get_file PROTO ((const char *, const char *, const char *, - char **, size_t *, size_t *)); -extern char *shell_escape PROTO((char *buf, const char *str)); -char *backup_file PROTO((const char *file, const char *suffix)); -extern void resolve_symlink PROTO ((char **filename)); -void sleep_past PROTO ((time_t desttime)); - -/* flags for run_exec(), the fast system() for CVS */ -#define RUN_NORMAL 0x0000 /* no special behaviour */ -#define RUN_COMBINED 0x0001 /* stdout is duped to stderr */ -#define RUN_REALLY 0x0002 /* do the exec, even if noexec is on */ -#define RUN_STDOUT_APPEND 0x0004 /* append to stdout, don't truncate */ -#define RUN_STDERR_APPEND 0x0008 /* append to stderr, don't truncate */ -#define RUN_SIGIGNORE 0x0010 /* ignore interrupts for command */ -#define RUN_TTY (char *)0 /* for the benefit of lint */ - -void run_add_arg_p PROTO ((int *, size_t *, char ***, const char *s)); -void run_arg_free_p PROTO ((int, char **)); -void run_arg PROTO((const char *s)); -void run_print PROTO((FILE * fp)); -void run_setup PROTO ((const char *prog)); -int run_exec PROTO((const char *stin, const char *stout, const char *sterr, - int flags)); - -/* other similar-minded stuff from run.c. */ -FILE *run_popen PROTO((const char *, const char *)); -int piped_child PROTO((const char **, int *, int *, int)); -void close_on_exec PROTO((int)); - -pid_t waitpid PROTO((pid_t, int *, int)); - -/* - * a struct vers_ts contains all the information about a file including the - * user and rcs file names, and the version checked out and the head. - * - * this is usually obtained from a call to Version_TS which takes a - * tag argument for the RCS file if desired - */ -struct vers_ts -{ - /* rcs version user file derives from, from CVS/Entries. - It can have the following special values: - - NULL = file is not mentioned in Entries (this is also used for a - directory). - "" = ILLEGAL! The comment used to say that it meant "no user file" - but as far as I know CVS didn't actually use it that way. - Note that according to cvs.texinfo, "" is not legal in the - Entries file. - 0 = user file is new - -vers = user file to be removed. */ - char *vn_user; - - /* Numeric revision number corresponding to ->vn_tag (->vn_tag - will often be symbolic). */ - char *vn_rcs; - /* If ->tag is a simple tag in the RCS file--a tag which really - exists which is not a magic revision--and if ->date is NULL, - then this is a copy of ->tag. Otherwise, it is a copy of - ->vn_rcs. */ - char *vn_tag; - - /* This is the timestamp from stating the file in the working directory. - It is NULL if there is no file in the working directory. It is - "Is-modified" if we know the file is modified but don't have its - contents. */ - char *ts_user; - /* Timestamp from CVS/Entries. For the server, ts_user and ts_rcs - are computed in a slightly different way, but the fact remains that - if they are equal the file in the working directory is unmodified - and if they differ it is modified. */ - char *ts_rcs; - - /* Options from CVS/Entries (keyword expansion), malloc'd. If none, - then it is an empty string (never NULL). */ - char *options; - - /* If non-NULL, there was a conflict (or merely a merge? See merge_file) - and the time stamp in this field is the time stamp of the working - directory file which was created with the conflict markers in it. - This is from CVS/Entries. */ - char *ts_conflict; - - /* Tag specified on the command line, or if none, tag stored in - CVS/Entries. */ - char *tag; - /* Date specified on the command line, or if none, date stored in - CVS/Entries. */ - char *date; - /* If this is 1, then tag is not a branch tag. If this is 0, then - tag may or may not be a branch tag. */ - int nonbranch; - - /* Pointer to entries file node */ - Entnode *entdata; - - /* Pointer to parsed src file info */ - RCSNode *srcfile; -}; -typedef struct vers_ts Vers_TS; - -Vers_TS *Version_TS PROTO ((struct file_info *finfo, char *options, char *tag, - char *date, int force_tag_match, - int set_time)); -void freevers_ts PROTO ((Vers_TS ** versp)); - -/* Miscellaneous CVS infrastructure which layers on top of the recursion - processor (for example, needs struct file_info). */ - -int Checkin PROTO ((int type, struct file_info *finfo, char *rev, - char *tag, char *options, char *message)); -int No_Difference PROTO ((struct file_info *finfo, Vers_TS *vers)); -/* TODO: can the finfo argument to special_file_mismatch be changed? -twp */ -int special_file_mismatch PROTO ((struct file_info *finfo, - char *rev1, char *rev2)); - -/* CVSADM_BASEREV stuff, from entries.c. */ -extern char *base_get PROTO ((struct file_info *)); -extern void base_register PROTO ((struct file_info *, char *)); -extern void base_deregister PROTO ((struct file_info *)); - -/* - * defines for Classify_File() to determine the current state of a file. - * These are also used as types in the data field for the list we make for - * Update_Logfile in commit, import, and add. - */ -enum classify_type -{ - T_UNKNOWN = 1, /* no old-style analog existed */ - T_CONFLICT, /* C (conflict) list */ - T_NEEDS_MERGE, /* G (needs merging) list */ - T_MODIFIED, /* M (needs checked in) list */ - T_CHECKOUT, /* O (needs checkout) list */ - T_ADDED, /* A (added file) list */ - T_REMOVED, /* R (removed file) list */ - T_REMOVE_ENTRY, /* W (removed entry) list */ - T_UPTODATE, /* File is up-to-date */ - T_PATCH, /* P Like C, but can patch */ - T_TITLE /* title for node type */ -}; -typedef enum classify_type Ctype; - -Ctype Classify_File PROTO - ((struct file_info *finfo, char *tag, char *date, char *options, - int force_tag_match, int aflag, Vers_TS **versp, int pipeout)); - -/* - * structure used for list nodes passed to Update_Logfile() and - * do_editor(). - */ -struct logfile_info -{ - enum classify_type type; - char *tag; - char *rev_old; /* rev number before a commit/modify, - NULL for add or import */ - char *rev_new; /* rev number after a commit/modify, - add, or import, NULL for remove */ -}; - -/* Wrappers. */ - -typedef enum { WRAP_MERGE, WRAP_COPY } WrapMergeMethod; -typedef enum { - /* -t and -f wrapper options. Treating directories as single files. */ - WRAP_TOCVS, - WRAP_FROMCVS, - /* -k wrapper option. Default keyword expansion options. */ - WRAP_RCSOPTION -} WrapMergeHas; - -void wrap_setup PROTO((void)); -int wrap_name_has PROTO((const char *name,WrapMergeHas has)); -char *wrap_rcsoption PROTO ((const char *fileName, int asFlag)); -char *wrap_tocvs_process_file PROTO((const char *fileName)); -int wrap_merge_is_copy PROTO((const char *fileName)); -void wrap_fromcvs_process_file PROTO ((const char *fileName)); -void wrap_add_file PROTO((const char *file,int temp)); -void wrap_add PROTO((char *line,int temp)); -void wrap_send PROTO ((void)); -#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) -void wrap_unparse_rcs_options PROTO ((char **, int)); -#endif /* SERVER_SUPPORT || CLIENT_SUPPORT */ - -/* Pathname expansion */ -char *expand_path PROTO((const char *name, const char *file, int line)); - -/* User variables. */ -extern List *variable_list; - -extern void variable_set PROTO ((char *nameval)); - -int watch PROTO ((int argc, char **argv)); -int edit PROTO ((int argc, char **argv)); -int unedit PROTO ((int argc, char **argv)); -int editors PROTO ((int argc, char **argv)); -int watchers PROTO ((int argc, char **argv)); -extern int annotate PROTO ((int argc, char **argv)); -extern int add PROTO ((int argc, char **argv)); -extern int admin PROTO ((int argc, char **argv)); -extern int checkout PROTO ((int argc, char **argv)); -extern int commit PROTO ((int argc, char **argv)); -extern int diff PROTO ((int argc, char **argv)); -extern int history PROTO ((int argc, char **argv)); -extern int import PROTO ((int argc, char **argv)); -extern int cvslog PROTO ((int argc, char **argv)); -#ifdef AUTH_CLIENT_SUPPORT -/* Some systems (namely Mac OS X) have conflicting definitions for these - * functions. Avoid them. - */ -#ifdef HAVE_LOGIN -# define login cvs_login -#endif /* HAVE_LOGIN */ -#ifdef HAVE_LOGOUT -# define logout cvs_logout -#endif /* HAVE_LOGOUT */ -extern int login PROTO((int argc, char **argv)); -extern int logout PROTO((int argc, char **argv)); -#endif /* AUTH_CLIENT_SUPPORT */ -extern int patch PROTO((int argc, char **argv)); -extern int release PROTO((int argc, char **argv)); -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 *)); - -#if defined(AUTH_CLIENT_SUPPORT) || defined(AUTH_SERVER_SUPPORT) -char *scramble PROTO ((char *str)); -char *descramble PROTO ((char *str)); -#endif /* AUTH_CLIENT_SUPPORT || AUTH_SERVER_SUPPORT */ - -#ifdef AUTH_CLIENT_SUPPORT -char *get_cvs_password PROTO((void)); -void free_cvs_password PROTO((char *str)); -int get_cvs_port_number PROTO((const cvsroot_t *root)); -char *normalize_cvsroot PROTO((const cvsroot_t *root)); -#endif /* AUTH_CLIENT_SUPPORT */ - -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)); -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 ((const char *, const char *)); diff --git a/contrib/cvs/src/cvsbug.in b/contrib/cvs/src/cvsbug.in deleted file mode 100755 index 07de151..0000000 --- a/contrib/cvs/src/cvsbug.in +++ /dev/null @@ -1,525 +0,0 @@ -#! /bin/sh -# Submit a problem report to a GNATS site. -# Copyright (C) 1993 Free Software Foundation, Inc. -# Contributed by Brendan Kehoe (brendan@cygnus.com), based on a -# version written by Heinz G. Seidl (hgs@ide.com). -# -# This file is part of GNU GNATS. -# Modified by Berliner for CVS. -# -# GNU GNATS is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# GNU GNATS is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# The version of this send-pr. -VERSION=3.2 - -# The submitter-id for your site. -SUBMITTER=net - -## # Where the GNATS directory lives, if at all. -## [ -z "$GNATS_ROOT" ] && -## GNATS_ROOT=/usr/local/lib/gnats/gnats-db - -# The default mail address for PR submissions. -GNATS_ADDR=@PACKAGE_BUGREPORT@ - -## # Where the gnats category tree lives. -## DATADIR=/usr/local/lib - -## # If we've been moved around, try using GCC_EXEC_PREFIX. -## [ ! -d $DATADIR/gnats -a -d "$GCC_EXEC_PREFIX" ] && DATADIR=${GCC_EXEC_PREFIX}.. - -# The default release for this host. -DEFAULT_RELEASE="@VERSION@" - -# The default organization. -DEFAULT_ORGANIZATION="net" - -## # The default site to look for. -## GNATS_SITE=unknown - -## # Newer config information? -## [ -f ${GNATS_ROOT}/gnats-adm/config ] && . ${GNATS_ROOT}/gnats-adm/config - -# Hack mktemp on systems that don't have it. -@MKTEMP_SH_FUNCTION@ -MKTEMP="@MKTEMP@" - -# What mailer to use. This must come after the config file, since it is -# host-dependent. -SENDMAIL="@SENDMAIL@" -MAIL_AGENT="$SENDMAIL -oi -t" -MAILER=`echo $MAIL_AGENT | sed -e 's, .*,,'` -if [ ! -f "$MAILER" ] ; then - echo "$COMMAND: Cannot find mail program \"$MAILER\"." - echo "$COMMAND: Please fix the MAIL_AGENT entry in the $COMMAND file." - exit 1 -fi - -if test "`echo -n foo`" = foo ; then - ECHON=bsd -elif test "`echo 'foo\c'`" = foo ; then - ECHON=sysv -else - ECHON=none -fi - -if [ $ECHON = bsd ] ; then - ECHON1="echo -n" - ECHON2= -elif [ $ECHON = sysv ] ; then - ECHON1=echo - ECHON2='\c' -else - ECHON1=echo - ECHON2= -fi - -# - -[ -z "$TMPDIR" ] && TMPDIR=/tmp - -TEMP="`$MKTEMP $TMPDIR/p.XXXXXX`" -BAD="`$MKTEMP $TMPDIR/pbad.XXXXXX`" -REF="`$MKTEMP $TMPDIR/pf.XXXXXX`" - -if [ -z "$LOGNAME" -a -n "$USER" ]; then - LOGNAME=$USER -fi - -FROM="$LOGNAME" -REPLY_TO="$LOGNAME" - -# Find out the name of the originator of this PR. -if [ -n "$NAME" ]; then - ORIGINATOR="$NAME" -elif [ -f $HOME/.fullname ]; then - ORIGINATOR="`sed -e '1q' $HOME/.fullname`" -elif [ -f /bin/domainname ]; then - if [ "`/bin/domainname`" != "" -a -f /usr/bin/ypcat ]; then - # Must use temp file due to incompatibilities in quoting behavior - # and to protect shell metacharacters in the expansion of $LOGNAME - /usr/bin/ypcat passwd 2>/dev/null | cat - /etc/passwd | grep "^$LOGNAME:" | - cut -f5 -d':' | sed -e 's/,.*//' > $TEMP - ORIGINATOR="`cat $TEMP`" - fi -fi - -if [ "$ORIGINATOR" = "" ]; then - grep "^$LOGNAME:" /etc/passwd | cut -f5 -d':' | sed -e 's/,.*//' > $TEMP - ORIGINATOR="`cat $TEMP`" -fi - -if [ -n "$ORGANIZATION" ]; then - if [ -f "$ORGANIZATION" ]; then - ORGANIZATION="`cat $ORGANIZATION`" - fi -else - if [ -n "$DEFAULT_ORGANIZATION" ]; then - ORGANIZATION="$DEFAULT_ORGANIZATION" - elif [ -f $HOME/.organization ]; then - ORGANIZATION="`cat $HOME/.organization`" - elif [ -f $HOME/.signature ]; then - ORGANIZATION="`cat $HOME/.signature`" - fi -fi - -# If they don't have a preferred editor set, then use -if [ -z "$VISUAL" ]; then - if [ -z "$EDITOR" ]; then - EDIT=vi - else - EDIT="$EDITOR" - fi -else - EDIT="$VISUAL" -fi - -# Find out some information. -SYSTEM=`( [ -f /bin/uname ] && /bin/uname -a ) || \ - ( [ -f /usr/bin/uname ] && /usr/bin/uname -a ) || echo ""` -ARCH=`[ -f /bin/arch ] && /bin/arch` -MACHINE=`[ -f /bin/machine ] && /bin/machine` - -COMMAND=`echo $0 | sed -e 's,.*/,,'` -## USAGE="Usage: $COMMAND [-PVL] [-t address] [-f filename] [--request-id] -USAGE="Usage: $COMMAND [-PVL] -[--version]" -REMOVE= -BATCH= - -while [ $# -gt 0 ]; do - case "$1" in - -r) ;; # Ignore for backward compat. -## -t | --to) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi -## shift ; GNATS_ADDR="$1" -## EXPLICIT_GNATS_ADDR=true -## ;; -## -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi -## shift ; IN_FILE="$1" -## if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then -## echo "$COMMAND: cannot read $IN_FILE" -## exit 1 -## fi -## ;; - -b | --batch) BATCH=true ;; - -p | -P | --print) PRINT=true ;; - -L | --list) FORMAT=norm ;; - -l | -CL | --lisp) FORMAT=lisp ;; -## --request-id) REQUEST_ID=true ;; - -h | --help) echo "$USAGE"; exit 0 ;; - -V | --version) echo "$VERSION"; exit 0 ;; - -*) echo "$USAGE" ; exit 1 ;; - *) echo "$USAGE" ; exit 1 -## if [ -z "$USER_GNATS_SITE" ]; then -## if [ ! -r "$DATADIR/gnats/$1" ]; then -## echo "$COMMAND: the GNATS site $1 does not have a categories list." -## exit 1 -## else -## # The site name is the alias they'll have to have created. -## USER_GNATS_SITE=$1 -## fi -## else -## echo "$USAGE" ; exit 1 -## fi - ;; - esac - shift -done - -if [ -n "$USER_GNATS_SITE" ]; then - GNATS_SITE=$USER_GNATS_SITE - GNATS_ADDR=$USER_GNATS_SITE-gnats -fi - -if [ "$SUBMITTER" = "unknown" -a -z "$REQUEST_ID" -a -z "$IN_FILE" ]; then - cat << '__EOF__' -It seems that send-pr is not installed with your unique submitter-id. -You need to run - - install-sid YOUR-SID - -where YOUR-SID is the identification code you received with `send-pr'. -`send-pr' will automatically insert this value into the template field -`>Submitter-Id'. If you've downloaded `send-pr' from the Net, use `net' -for this value. If you do not know your id, run `send-pr --request-id' to -get one from your support site. -__EOF__ - exit 1 -fi - -## if [ -r "$DATADIR/gnats/$GNATS_SITE" ]; then -## CATEGORIES=`grep -v '^#' $DATADIR/gnats/$GNATS_SITE | sort` -## else -## echo "$COMMAND: could not read $DATADIR/gnats/$GNATS_SITE for categories list." -## exit 1 -## fi -CATEGORIES="contrib cvs doc pcl-cvs portability" - -if [ -z "$CATEGORIES" ]; then - echo "$COMMAND: the categories list for $GNATS_SITE was empty!" - exit 1 -fi - -case "$FORMAT" in - lisp) echo "$CATEGORIES" | \ - awk 'BEGIN {printf "( "} - {printf "(\"%s\") ",$0} - END {printf ")\n"}' - exit 0 - ;; - norm) l=`echo "$CATEGORIES" | \ - awk 'BEGIN {max = 0; } - { if (length($0) > max) { max = length($0); } } - END {print max + 1;}'` - c=`expr 70 / $l` - if [ $c -eq 0 ]; then c=1; fi - echo "$CATEGORIES" | \ - awk 'BEGIN {print "Known categories:"; i = 0 } - { printf ("%-'$l'.'$l's", $0); if ((++i % '$c') == 0) { print "" } } - END { print ""; }' - exit 0 - ;; -esac - -ORIGINATOR_C='<name of the PR author (one line)>' -ORGANIZATION_C='<organization of PR author (multiple lines)>' -CONFIDENTIAL_C='<[ yes | no ] (one line)>' -SYNOPSIS_C='<synopsis of the problem (one line)>' -SEVERITY_C='<[ non-critical | serious | critical ] (one line)>' -PRIORITY_C='<[ low | medium | high ] (one line)>' -CATEGORY_C='<name of the product (one line)>' -CLASS_C='<[ sw-bug | doc-bug | change-request | support ] (one line)>' -RELEASE_C='<release number or tag (one line)>' -ENVIRONMENT_C='<machine, os, target, libraries (multiple lines)>' -DESCRIPTION_C='<precise description of the problem (multiple lines)>' -HOW_TO_REPEAT_C='<code/input/activities to reproduce the problem (multiple lines)>' -FIX_C='<how to correct or work around the problem, if known (multiple lines)>' - -# Catch some signals. ($xs kludge needed by Sun /bin/sh) -xs=0 -trap 'rm -f $REF $TEMP; exit $xs' 0 -trap 'echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP; xs=1; exit' 1 2 3 13 15 - -# If they told us to use a specific file, then do so. -if [ -n "$IN_FILE" ]; then - if [ "$IN_FILE" = "-" ]; then - # The PR is coming from the standard input. - if [ -n "$EXPLICIT_GNATS_ADDR" ]; then - sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" > $TEMP - else - cat > $TEMP - fi - else - # Use the file they named. - if [ -n "$EXPLICIT_GNATS_ADDR" ]; then - sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" $IN_FILE > $TEMP - else - cat $IN_FILE > $TEMP - fi - fi -else - - if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then - # If their PR_FORM points to a bogus entry, then bail. - if [ ! -f "$PR_FORM" -o ! -r "$PR_FORM" -o ! -s "$PR_FORM" ]; then - echo "$COMMAND: can't seem to read your template file (\`$PR_FORM'), ignoring PR_FORM" - sleep 1 - PRINT_INTERN=bad_prform - fi - fi - - if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then - cp $PR_FORM $TEMP || - ( echo "$COMMAND: could not copy $PR_FORM" ; xs=1; exit ) - else - for file in $TEMP $REF ; do - cat > $file << '__EOF__' -SEND-PR: -*- send-pr -*- -SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as -SEND-PR: will all comments (text enclosed in `<' and `>'). -SEND-PR: -SEND-PR: Choose from the following categories: -SEND-PR: -__EOF__ - - # Format the categories so they fit onto lines. - l=`echo "$CATEGORIES" | \ - awk 'BEGIN {max = 0; } - { if (length($0) > max) { max = length($0); } } - END {print max + 1;}'` - c=`expr 61 / $l` - if [ $c -eq 0 ]; then c=1; fi - echo "$CATEGORIES" | \ - awk 'BEGIN {printf "SEND-PR: "; i = 0 } - { printf ("%-'$l'.'$l's", $0); - if ((++i % '$c') == 0) { printf "\nSEND-PR: " } } - END { printf "\nSEND-PR:\n"; }' >> $file - - cat >> $file << __EOF__ -To: $GNATS_ADDR -Subject: -From: $FROM -Reply-To: $REPLY_TO -X-send-pr-version: $VERSION - - ->Submitter-Id: $SUBMITTER ->Originator: $ORIGINATOR ->Organization: -${ORGANIZATION-$ORGANIZATION_C} ->Confidential: $CONFIDENTIAL_C ->Synopsis: $SYNOPSIS_C ->Severity: $SEVERITY_C ->Priority: $PRIORITY_C ->Category: $CATEGORY_C ->Class: $CLASS_C ->Release: ${DEFAULT_RELEASE-$RELEASE_C} ->Environment: - $ENVIRONMENT_C -`[ -n "$SYSTEM" ] && echo System: $SYSTEM` -`[ -n "$ARCH" ] && echo Architecture: $ARCH` -`[ -n "$MACHINE" ] && echo Machine: $MACHINE` ->Description: - $DESCRIPTION_C ->How-To-Repeat: - $HOW_TO_REPEAT_C ->Fix: - $FIX_C -__EOF__ - done - fi - - if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then - cat $TEMP - xs=0; exit - fi - - chmod u+w $TEMP - if [ -z "$REQUEST_ID" ]; then - eval $EDIT $TEMP - else - ed -s $TEMP << '__EOF__' -/^Subject/s/^Subject:.*/Subject: request for a customer id/ -/^>Category/s/^>Category:.*/>Category: send-pr/ -w -q -__EOF__ - fi - - if cmp -s $REF $TEMP ; then - echo "$COMMAND: problem report not filled out, therefore not sent" - xs=1; exit - fi -fi - -# -# Check the enumeration fields - -# This is a "sed-subroutine" with one keyword parameter -# (with workaround for Sun sed bug) -# -SED_CMD=' -/$PATTERN/{ -s||| -s|<.*>|| -s|^[ ]*|| -s|[ ]*$|| -p -q -}' - - -while [ -z "$REQUEST_ID" ]; do - CNT=0 - - # 1) Confidential - # - PATTERN=">Confidential:" - CONFIDENTIAL=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$CONFIDENTIAL" in - ""|yes|no) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$CONFIDENTIAL' is not a valid value for \`Confidential'." ;; - esac - # - # 2) Severity - # - PATTERN=">Severity:" - SEVERITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$SEVERITY" in - ""|non-critical|serious|critical) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$SEVERITY' is not a valid value for \`Severity'." - esac - # - # 3) Priority - # - PATTERN=">Priority:" - PRIORITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$PRIORITY" in - ""|low|medium|high) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$PRIORITY' is not a valid value for \`Priority'." - esac - # - # 4) Category - # - PATTERN=">Category:" - CATEGORY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - FOUND= - for C in $CATEGORIES - do - if [ "$C" = "$CATEGORY" ]; then FOUND=true ; break ; fi - done - if [ -n "$FOUND" ]; then - CNT=`expr $CNT + 1` - else - if [ -z "$CATEGORY" ]; then - echo "$COMMAND: you must include a Category: field in your report." - else - echo "$COMMAND: \`$CATEGORY' is not a known category." - fi - fi - # - # 5) Class - # - PATTERN=">Class:" - CLASS=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$CLASS" in - ""|sw-bug|doc-bug|change-request|support) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$CLASS' is not a valid value for \`Class'." - esac - - [ $CNT -lt 5 -a -z "$BATCH" ] && - echo "Errors were found with the problem report." - - while true; do - if [ -z "$BATCH" ]; then - $ECHON1 "a)bort, e)dit or s)end? $ECHON2" - read input - else - if [ $CNT -eq 5 ]; then - input=s - else - input=a - fi - fi - case "$input" in - a*) - if [ -z "$BATCH" ]; then - echo "$COMMAND: the problem report remains in $BAD and is not sent." - mv $TEMP $BAD - else - echo "$COMMAND: the problem report is not sent." - fi - xs=1; exit - ;; - e*) - eval $EDIT $TEMP - continue 2 - ;; - s*) - break 2 - ;; - esac - done -done -# -# Remove comments and send the problem report -# (we have to use patterns, where the comment contains regex chars) -# -# /^>Originator:/s;$ORIGINATOR;; -sed -e " -/^SEND-PR:/d -/^>Organization:/,/^>[A-Za-z-]*:/s;$ORGANIZATION_C;; -/^>Confidential:/s;<.*>;; -/^>Synopsis:/s;$SYNOPSIS_C;; -/^>Severity:/s;<.*>;; -/^>Priority:/s;<.*>;; -/^>Category:/s;$CATEGORY_C;; -/^>Class:/s;<.*>;; -/^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C;; -/^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C;; -/^>Description:/,/^>[A-Za-z-]*:/s;$DESCRIPTION_C;; -/^>How-To-Repeat:/,/^>[A-Za-z-]*:/s;$HOW_TO_REPEAT_C;; -/^>Fix:/,/^>[A-Za-z-]*:/s;$FIX_C;; -" $TEMP > $REF - -if $MAIL_AGENT < $REF; then - echo "$COMMAND: problem report sent" - xs=0; exit -else - echo "$COMMAND: mysterious mail failure." - if [ -z "$BATCH" ]; then - echo "$COMMAND: the problem report remains in $BAD and is not sent." - mv $REF $BAD - else - echo "$COMMAND: the problem report is not sent." - fi - xs=1; exit -fi diff --git a/contrib/cvs/src/cvsrc.c b/contrib/cvs/src/cvsrc.c deleted file mode 100644 index 60de909..0000000 --- a/contrib/cvs/src/cvsrc.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1993 david d zuhn - * - * Written by david d `zoo' zuhn while at Cygnus Support - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - */ - - -#include "cvs.h" -#include "getline.h" - -/* this file is to be found in the user's home directory */ - -#ifndef CVSRC_FILENAME -#define CVSRC_FILENAME ".cvsrc" -#endif -char cvsrc[] = CVSRC_FILENAME; - -#define GROW 10 - -extern char *strtok (); - -/* Read cvsrc, processing options matching CMDNAME ("cvs" for global - options, and update *ARGC and *ARGV accordingly. */ - -void -read_cvsrc (argc, argv, cmdname) - int *argc; - char ***argv; - const char *cmdname; -{ - char *homedir; - char *homeinit; - FILE *cvsrcfile; - - char *line; - int line_length; - size_t line_chars_allocated; - - char *optstart; - - int command_len; - int found = 0; - - int i; - - int new_argc; - int max_new_argv; - char **new_argv; - - /* old_argc and old_argv hold the values returned from the - previous invocation of read_cvsrc and are used to free the - allocated memory. The first invocation of read_cvsrc gets argv - from the system, this memory must not be free'd. */ - static int old_argc = 0; - static char **old_argv = NULL; - - /* don't do anything if argc is -1, since that implies "help" mode */ - if (*argc == -1) - return; - - /* determine filename for ~/.cvsrc */ - - homedir = get_homedir (); - /* If we can't find a home directory, ignore ~/.cvsrc. This may - make tracking down problems a bit of a pain, but on the other - hand it might be obnoxious to complain when CVS will function - just fine without .cvsrc (and many users won't even know what - .cvsrc is). */ - if (!homedir) - return; - - homeinit = strcat_filename_onto_homedir (homedir, cvsrc); - - /* if it can't be read, there's no point to continuing */ - - if (!isreadable (homeinit)) - { - free (homeinit); - return; - } - - /* now scan the file until we find the line for the command in question */ - - line = NULL; - line_chars_allocated = 0; - command_len = strlen (cmdname); - cvsrcfile = open_file (homeinit, "r"); - while ((line_length = getline (&line, &line_chars_allocated, cvsrcfile)) - >= 0) - { - /* skip over comment lines */ - if (line[0] == '#') - continue; - - /* stop if we match the current command */ - if (!strncmp (line, cmdname, command_len) - && isspace ((unsigned char) *(line + command_len))) - { - found = 1; - break; - } - } - - if (line_length < 0 && !feof (cvsrcfile)) - error (0, errno, "cannot read %s", homeinit); - - fclose (cvsrcfile); - - /* setup the new options list */ - - new_argc = 1; - max_new_argv = (*argc) + GROW; - new_argv = (char **) xmalloc (max_new_argv * sizeof (char*)); - new_argv[0] = xstrdup ((*argv)[0]); - - if (found) - { - /* skip over command in the options line */ - for (optstart = strtok (line + command_len, "\t \n\r"); - optstart; - optstart = strtok (NULL, "\t \n\r")) - { - new_argv [new_argc++] = xstrdup (optstart); - - if (new_argc >= max_new_argv) - { - max_new_argv += GROW; - new_argv = (char **) xrealloc (new_argv, max_new_argv * sizeof (char*)); - } - } - } - - if (line != NULL) - free (line); - - /* now copy the remaining arguments */ - - if (new_argc + *argc > max_new_argv) - { - max_new_argv = new_argc + *argc; - new_argv = (char **) xrealloc (new_argv, max_new_argv * sizeof (char*)); - } - for (i=1; i < *argc; i++) - { - new_argv [new_argc++] = xstrdup ((*argv)[i]); - } - - if (old_argv != NULL) - { - /* Free the memory which was allocated in the previous - read_cvsrc call. */ - free_names (&old_argc, old_argv); - } - - old_argc = *argc = new_argc; - old_argv = *argv = new_argv; - - free (homeinit); - return; -} diff --git a/contrib/cvs/src/diff.c b/contrib/cvs/src/diff.c deleted file mode 100644 index 8a61f9a..0000000 --- a/contrib/cvs/src/diff.c +++ /dev/null @@ -1,1178 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Difference - * - * Run diff against versions in the repository. Options that are specified are - * passed on directly to "rcsdiff". - * - * Without any file arguments, runs diff against all the currently modified - * files. - * - * $FreeBSD$ - */ - -#include <assert.h> -#include "cvs.h" - -enum diff_file -{ - DIFF_ERROR, - DIFF_ADDED, - DIFF_REMOVED, - DIFF_DIFFERENT, - DIFF_SAME -}; - -static Dtype diff_dirproc PROTO ((void *callerdat, const char *dir, - const char *pos_repos, - const char *update_dir, - List *entries)); -static int diff_filesdoneproc PROTO ((void *callerdat, int err, - const char *repos, - const char *update_dir, - List *entries)); -static int diff_dirleaveproc PROTO ((void *callerdat, const char *dir, - int err, const char *update_dir, - List *entries)); -static enum diff_file diff_file_nodiff PROTO(( struct file_info *finfo, - Vers_TS *vers, - enum diff_file, - char **rev1_cache )); -static int diff_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static void diff_mark_errors PROTO((int err)); - - -/* Global variables. Would be cleaner if we just put this stuff in a - struct like log.c does. */ - -/* Command line tags, from -r option. Points into argv. */ -static char *diff_rev1, *diff_rev2; -/* Command line dates, from -D option. Malloc'd. */ -static char *diff_date1, *diff_date2; -static char *diff_join1, *diff_join2; -static char *use_rev1, *use_rev2; -static int have_rev1_label, have_rev2_label; - -/* Revision of the user file, if it is unchanged from something in the - repository and we want to use that fact. */ -static char *user_file_rev; - -static char *options; -static char **diff_argv; -static int diff_argc; -static size_t diff_arg_allocated; -static int diff_errors; -static int empty_files = 0; - -static const char *const diff_usage[] = -{ - "Usage: %s %s [-lR] [-k kopt] [format_options]\n", - " [[-r rev1 | -D date1] [-r rev2 | -D date2]] [files...] \n", - "\t-l\tLocal directory only, not recursive\n", - "\t-R\tProcess directories recursively.\n", - "\t-k kopt\tSpecify keyword expansion mode.\n", - "\t-D d1\tDiff revision for date against working file.\n", - "\t-D d2\tDiff rev1/date1 against date2.\n", - "\t-r rev1\tDiff revision for rev1 against working file.\n", - "\t-r rev2\tDiff rev1/date1 against rev2.\n", - "\nformat_options:\n", - " -i --ignore-case Consider upper- and lower-case to be the same.\n", - " -w --ignore-all-space Ignore all white space.\n", - " -b --ignore-space-change Ignore changes in the amount of white space.\n", - " -B --ignore-blank-lines Ignore changes whose lines are all blank.\n", - " -I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.\n", - " --binary Read and write data in binary mode.\n", - " -a --text Treat all files as text.\n\n", - " -c -C NUM --context[=NUM] Output NUM (default 2) lines of copied context.\n", - " -u -U NUM --unified[=NUM] Output NUM (default 2) lines of unified context.\n", - " -NUM Use NUM context lines.\n", - " -L LABEL --label LABEL Use LABEL instead of file name.\n", - " -p --show-c-function Show which C function each change is in.\n", - " -F RE --show-function-line=RE Show the most recent line matching RE.\n", - " --brief Output only whether files differ.\n", - " -e --ed Output an ed script.\n", - " -f --forward-ed Output something like an ed script in forward order.\n", - " -n --rcs Output an RCS format diff.\n", - " -y --side-by-side Output in two columns.\n", - " -W NUM --width=NUM Output at most NUM (default 130) characters per line.\n", - " --left-column Output only the left column of common lines.\n", - " --suppress-common-lines Do not output common lines.\n", - " --ifdef=NAME Output merged file to show `#ifdef NAME' diffs.\n", - " --GTYPE-group-format=GFMT Similar, but format GTYPE input groups with GFMT.\n", - " --line-format=LFMT Similar, but format all input lines with LFMT.\n", - " --LTYPE-line-format=LFMT Similar, but format LTYPE input lines with LFMT.\n", - " LTYPE is `old', `new', or `unchanged'. GTYPE is LTYPE or `changed'.\n", - " GFMT may contain:\n", - " %%< lines from FILE1\n", - " %%> lines from FILE2\n", - " %%= lines common to FILE1 and FILE2\n", - " %%[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER\n", - " LETTERs are as follows for new group, lower case for old group:\n", - " F first line number\n", - " L last line number\n", - " N number of lines = L-F+1\n", - " E F-1\n", - " M L+1\n", - " LFMT may contain:\n", - " %%L contents of line\n", - " %%l contents of line, excluding any trailing newline\n", - " %%[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number\n", - " Either GFMT or LFMT may contain:\n", - " %%%% %%\n", - " %%c'C' the single character C\n", - " %%c'\\OOO' the character with octal code OOO\n\n", - " -t --expand-tabs Expand tabs to spaces in output.\n", - " -T --initial-tab Make tabs line up by prepending a tab.\n\n", - " -N --new-file Treat absent files as empty.\n", - " -s --report-identical-files Report when two files are the same.\n", - " --horizon-lines=NUM Keep NUM lines of the common prefix and suffix.\n", - " -d --minimal Try hard to find a smaller set of changes.\n", - " -H --speed-large-files Assume large files and many scattered small changes.\n", - "\n(Specify the --help global option for a list of other help options)\n", - NULL -}; - -/* I copied this array directly out of diff.c in diffutils 2.7, after - removing the following entries, none of which seem relevant to use - with CVS: - --help - --version (-v) - --recursive (-r) - --unidirectional-new-file (-P) - --starting-file (-S) - --exclude (-x) - --exclude-from (-X) - --sdiff-merge-assist - --paginate (-l) (doesn't work with library callbacks) - - I changed the options which take optional arguments (--context and - --unified) to return a number rather than a letter, so that the - optional argument could be handled more easily. I changed the - --brief and --ifdef options to return numbers, since -q and -D mean - something else to cvs diff. - - The numbers 129- that appear in the fourth element of some entries - tell the big switch in `diff' how to process those options. -- Ian - - The following options, which diff lists as "An alias, no longer - recommended" have been removed: --file-label --entire-new-file - --ascii --print. */ - -static struct option const longopts[] = -{ - {"ignore-blank-lines", 0, 0, 'B'}, - {"context", 2, 0, 143}, - {"ifdef", 1, 0, 131}, - {"show-function-line", 1, 0, 'F'}, - {"speed-large-files", 0, 0, 'H'}, - {"ignore-matching-lines", 1, 0, 'I'}, - {"label", 1, 0, 'L'}, - {"new-file", 0, 0, 'N'}, - {"initial-tab", 0, 0, 'T'}, - {"width", 1, 0, 'W'}, - {"text", 0, 0, 'a'}, - {"ignore-space-change", 0, 0, 'b'}, - {"minimal", 0, 0, 'd'}, - {"ed", 0, 0, 'e'}, - {"forward-ed", 0, 0, 'f'}, - {"ignore-case", 0, 0, 'i'}, - {"rcs", 0, 0, 'n'}, - {"show-c-function", 0, 0, 'p'}, - - /* This is a potentially very useful option, except the output is so - silly. It would be much better for it to look like "cvs rdiff -s" - which displays all the same info, minus quite a few lines of - extraneous garbage. */ - {"brief", 0, 0, 145}, - - {"report-identical-files", 0, 0, 's'}, - {"expand-tabs", 0, 0, 't'}, - {"ignore-all-space", 0, 0, 'w'}, - {"side-by-side", 0, 0, 'y'}, - {"unified", 2, 0, 146}, - {"left-column", 0, 0, 129}, - {"suppress-common-lines", 0, 0, 130}, - {"old-line-format", 1, 0, 132}, - {"new-line-format", 1, 0, 133}, - {"unchanged-line-format", 1, 0, 134}, - {"line-format", 1, 0, 135}, - {"old-group-format", 1, 0, 136}, - {"new-group-format", 1, 0, 137}, - {"unchanged-group-format", 1, 0, 138}, - {"changed-group-format", 1, 0, 139}, - {"horizon-lines", 1, 0, 140}, - {"binary", 0, 0, 142}, - {0, 0, 0, 0} -}; - - - -/* Add one of OPT or LONGOPT, and ARGUMENT, when present, to global DIFF_ARGV. - * - * INPUTS - * opt A character option representation. - * longopt A long option name. - * argument Optional option argument. - * - * GLOBALS - * diff_argc The number of arguments in DIFF_ARGV. - * diff_argv Array of argument strings. - * diff_arg_allocated Allocated length of DIFF_ARGV. - * - * NOTES - * Behavior when both OPT & LONGOPT are provided is undefined. - * - * RETURNS - * Nothing. - */ -static void -add_diff_args (char opt, const char *longopt, const char *argument) -{ - char *tmp; - - /* Add opt or longopt to diff_arv. */ - assert (opt || (longopt && *longopt)); - assert (!(opt && (longopt && *longopt))); - if (opt) - { - tmp = xmalloc (3); - sprintf (tmp, "-%c", opt); - } - else - { - tmp = xmalloc (3 + strlen (longopt)); - sprintf (tmp, "--%s", longopt); - } - run_add_arg_p (&diff_argc, &diff_arg_allocated, &diff_argv, tmp); - free (tmp); - - /* When present, add ARGUMENT to DIFF_ARGV. */ - if (argument) - run_add_arg_p (&diff_argc, &diff_arg_allocated, &diff_argv, argument); -} - - - -/* CVS 1.9 and similar versions seemed to have pretty weird handling - of -y and -T. In the cases where it called rcsdiff, - they would have the meanings mentioned below. In the cases where it - called diff, they would have the meanings mentioned in "longopts". - Noone seems to have missed them, so I think the right thing to do is - just to remove the options altogether (which I have done). - - In the case of -z and -q, "cvs diff" did not accept them even back - when we called rcsdiff (at least, it hasn't accepted them - recently). - - In comparing rcsdiff to the new CVS implementation, I noticed that - the following rcsdiff flags are not handled by CVS diff: - - -y: perform diff even when the requested revisions are the - same revision number - -q: run quietly - -T: preserve modification time on the RCS file - -z: specify timezone for use in file labels - - I think these are not really relevant. -y is undocumented even in - RCS 5.7, and seems like a minor change at best. According to RCS - documentation, -T only applies when a RCS file has been modified - because of lock changes; doesn't CVS sidestep RCS's entire lock - structure? -z seems to be unsupported by CVS diff, and has a - different meaning as a global option anyway. (Adding it could be - a feature, but if it is left out for now, it should not break - anything.) For the purposes of producing output, CVS diff appears - mostly to ignore -q. Maybe this should be fixed, but I think it's - a larger issue than the changes included here. */ - -int -diff (argc, argv) - int argc; - char **argv; -{ - int c, err = 0; - int local = 0; - int which; - int option_index; - - if (argc == -1) - usage (diff_usage); - - have_rev1_label = have_rev2_label = 0; - - /* - * Note that we catch all the valid arguments here, so that we can - * intercept the -r arguments for doing revision diffs; and -l/-R for a - * non-recursive/recursive diff. - */ - - /* Clean out our global variables (multiroot can call us multiple - times and the server can too, if the client sends several - diff commands). */ - if (diff_argc) - { - run_arg_free_p (diff_argc, diff_argv); - diff_argc = 0; - } - diff_rev1 = NULL; - diff_rev2 = NULL; - diff_date1 = NULL; - diff_date2 = NULL; - diff_join1 = NULL; - diff_join2 = NULL; - - optind = 0; - /* FIXME: This should really be allocating an argv to be passed to diff - * later rather than strcatting onto the opts variable. We have some - * handling routines that can already handle most of the argc/argv - * maintenance for us and currently, if anyone were to attempt to pass a - * quoted string in here, it would be split on spaces and tabs on its way - * to diff. - */ - while ((c = getopt_long (argc, argv, - "+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:W:k:r:j:", - longopts, &option_index)) != -1) - { - switch (c) - { - case 'y': - add_diff_args (0, "side-by-side", NULL); - break; - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'h': case 'i': case 'n': case 'p': case 's': case 't': - case 'u': case 'w': - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - case 'B': case 'H': case 'T': - add_diff_args (c, NULL, NULL); - break; - case 'L': - if (have_rev1_label++) - if (have_rev2_label++) - { - error (0, 0, "extra -L arguments ignored"); - break; - } - /* Fall through. */ - case 'C': case 'F': case 'I': case 'U': case 'W': - add_diff_args (c, NULL, optarg); - break; - case 129: case 130: case 131: case 132: case 133: case 134: - case 135: case 136: case 137: case 138: case 139: case 140: - case 141: case 142: case 143: case 145: case 146: - add_diff_args (0, longopts[option_index].name, - longopts[option_index].has_arg ? optarg : NULL); - break; - case 'R': - local = 0; - break; - case 'l': - local = 1; - break; - case 'k': - if (options) - free (options); - options = RCS_check_kflag (optarg); - break; - case 'j': - { - char *ptr; - char *cpy = strdup(optarg); - - if ((ptr = strchr(optarg, ':')) != NULL) - *ptr++ = 0; - if (diff_rev2 != NULL || diff_date2 != NULL) - error (1, 0, - "no more than two revisions/dates can be specified"); - if (diff_rev1 != NULL || diff_date1 != NULL) { - diff_join2 = cpy; - diff_rev2 = optarg; - diff_date2 = ptr ? Make_Date(ptr) : NULL; - } else { - diff_join1 = cpy; - diff_rev1 = optarg; - diff_date1 = ptr ? Make_Date(ptr) : NULL; - } - } - break; - case 'r': - if (diff_rev2 != NULL || diff_date2 != NULL) - error (1, 0, - "no more than two revisions/dates can be specified"); - if (diff_rev1 != NULL || diff_date1 != NULL) - diff_rev2 = optarg; - else - diff_rev1 = optarg; - break; - case 'D': - if (diff_rev2 != NULL || diff_date2 != NULL) - error (1, 0, - "no more than two revisions/dates can be specified"); - if (diff_rev1 != NULL || diff_date1 != NULL) - diff_date2 = Make_Date (optarg); - else - diff_date1 = Make_Date (optarg); - break; - case 'N': - empty_files = 1; - break; - case '?': - default: - usage (diff_usage); - break; - } - } - argc -= optind; - argv += optind; - - /* make sure options is non-null */ - if (!options) - options = xstrdup (""); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - send_arg("-l"); - if (empty_files) - send_arg("-N"); - send_options (diff_argc, diff_argv); - if (options[0] != '\0') - send_arg (options); - if (diff_join1) - option_with_arg ("-j", diff_join1); - else if (diff_rev1) - option_with_arg ("-r", diff_rev1); - else if (diff_date1) - client_senddate (diff_date1); - - if (diff_join2) - option_with_arg ("-j", diff_join2); - else if (diff_rev2) - option_with_arg ("-r", diff_rev2); - else if (diff_date2) - client_senddate (diff_date2); - send_arg ("--"); - - /* Send the current files unless diffing two revs from the archive */ - if (diff_rev2 == NULL && diff_date2 == NULL) - send_files (argc, argv, local, 0, 0); - else - send_files (argc, argv, local, 0, SEND_NO_CONTENTS); - - send_file_names (argc, argv, SEND_EXPAND_WILD); - - send_to_server ("diff\012", 0); - err = get_responses_and_close (); - } else -#endif - { /* FreeBSD addition - warning idention not changed til matching-} */ - if (diff_rev1 != NULL) - tag_check_valid (diff_rev1, argc, argv, local, 0, ""); - if (diff_rev2 != NULL) - tag_check_valid (diff_rev2, argc, argv, local, 0, ""); - - which = W_LOCAL; - if (diff_rev1 != NULL || diff_date1 != NULL) - which |= W_REPOS | W_ATTIC; - - wrap_setup (); - - /* start the recursion processor */ - err = start_recursion (diff_fileproc, diff_filesdoneproc, diff_dirproc, - diff_dirleaveproc, NULL, argc, argv, local, - which, 0, CVS_LOCK_READ, (char *) NULL, 1, - (char *) NULL); - } /* FreeBSD addition */ - - /* clean up */ - free (options); - options = NULL; - - if (diff_date1 != NULL) - free (diff_date1); - if (diff_date2 != NULL) - free (diff_date2); - if (diff_join1 != NULL) - free (diff_join1); - if (diff_join2 != NULL) - free (diff_join2); - - return (err); -} - -/* - * Do a file diff - */ -/* ARGSUSED */ -static int -diff_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - int status, err = 2; /* 2 == trouble, like rcsdiff */ - Vers_TS *vers; - enum diff_file empty_file = DIFF_DIFFERENT; - char *tmp = NULL; - char *tocvsPath = NULL; - char *fname = NULL; - char *label1; - char *label2; - char *rev1_cache = NULL; - - user_file_rev = 0; - vers = Version_TS (finfo, NULL, NULL, NULL, 1, 0); - - if (diff_rev2 != NULL || diff_date2 != NULL) - { - /* Skip all the following checks regarding the user file; we're - not using it. */ - } - else if (vers->vn_user == NULL) - { - /* The file does not exist in the working directory. */ - if ((diff_rev1 != NULL || diff_date1 != NULL) - && vers->srcfile != NULL) - { - /* The file does exist in the repository. */ - if (empty_files) - empty_file = DIFF_REMOVED; - else - { - int exists; - - exists = 0; - /* special handling for TAG_HEAD */ - if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0) - { - char *head = - (vers->vn_rcs == NULL - ? NULL - : RCS_branch_head (vers->srcfile, vers->vn_rcs)); - exists = head != NULL && !RCS_isdead(vers->srcfile, head); - if (head != NULL) - free (head); - } - else - { - Vers_TS *xvers; - - xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, - 1, 0); - exists = xvers->vn_rcs != NULL && !RCS_isdead(xvers->srcfile, xvers->vn_rcs); - freevers_ts (&xvers); - } - if (exists) - error (0, 0, - "%s no longer exists, no comparison available", - finfo->fullname); - goto out; - } - } - else - { - error (0, 0, "I know nothing about %s", finfo->fullname); - goto out; - } - } - else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') - { - /* The file was added locally. */ - int exists = 0; - - if (vers->srcfile != NULL) - { - /* The file does exist in the repository. */ - - if ((diff_rev1 != NULL || diff_date1 != NULL)) - { - /* special handling for TAG_HEAD */ - if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0) - { - char *head = - (vers->vn_rcs == NULL - ? NULL - : RCS_branch_head (vers->srcfile, vers->vn_rcs)); - exists = head != NULL && !RCS_isdead(vers->srcfile, head); - if (head != NULL) - free (head); - } - else - { - Vers_TS *xvers; - - xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, - 1, 0); - exists = xvers->vn_rcs != NULL - && !RCS_isdead (xvers->srcfile, xvers->vn_rcs); - freevers_ts (&xvers); - } - } - else - { - /* The file was added locally, but an RCS archive exists. Our - * base revision must be dead. - */ - /* No need to set, exists = 0, here. That's the default. */ - } - } - if (!exists) - { - /* If we got here, then either the RCS archive does not exist or - * the relevant revision is dead. - */ - if (empty_files) - empty_file = DIFF_ADDED; - else - { - error (0, 0, "%s is a new entry, no comparison available", - finfo->fullname); - goto out; - } - } - } - else if (vers->vn_user[0] == '-') - { - if (empty_files) - empty_file = DIFF_REMOVED; - else - { - error (0, 0, "%s was removed, no comparison available", - finfo->fullname); - goto out; - } - } - else - { - if (vers->vn_rcs == NULL && vers->srcfile == NULL) - { - error (0, 0, "cannot find revision control file for %s", - finfo->fullname); - goto out; - } - else - { - if (vers->ts_user == NULL) - { - error (0, 0, "cannot find %s", finfo->fullname); - goto out; - } - else if (!strcmp (vers->ts_user, vers->ts_rcs)) - { - /* The user file matches some revision in the repository - Diff against the repository (for remote CVS, we might not - have a copy of the user file around). */ - user_file_rev = vers->vn_user; - } - } - } - - empty_file = diff_file_nodiff( finfo, vers, empty_file, &rev1_cache ); - if( empty_file == DIFF_SAME ) - { - /* In the server case, would be nice to send a "Checked-in" - response, so that the client can rewrite its timestamp. - server_checked_in by itself isn't the right thing (it - needs a server_register), but I'm not sure what is. - It isn't clear to me how "cvs status" handles this (that - is, for a client which sends Modified not Is-modified to - "cvs status"), but it does. */ - err = 0; - goto out; - } - else if( empty_file == DIFF_ERROR ) - goto out; - - /* Output an "Index:" line for patch to use */ - cvs_output ("Index: ", 0); - cvs_output (finfo->fullname, 0); - cvs_output ("\n", 1); - - tocvsPath = wrap_tocvs_process_file(finfo->file); - if( tocvsPath != NULL ) - { - /* Backup the current version of the file to CVS/,,filename */ - fname = xmalloc (strlen (finfo->file) - + sizeof CVSADM - + sizeof CVSPREFIX - + 10); - sprintf(fname,"%s/%s%s",CVSADM, CVSPREFIX, finfo->file); - if (unlink_file_dir (fname) < 0) - if (! existence_error (errno)) - error (1, errno, "cannot remove %s", fname); - rename_file (finfo->file, fname); - /* Copy the wrapped file to the current directory then go to work */ - copy_file (tocvsPath, finfo->file); - } - - /* Set up file labels appropriate for compatibility with the Larry Wall - * implementation of patch if the user didn't specify. This is irrelevant - * according to the POSIX.2 specification. - */ - label1 = NULL; - label2 = NULL; - if (!have_rev1_label) - { - if (empty_file == DIFF_ADDED) - label1 = - make_file_label (DEVNULL, NULL, NULL); - else - label1 = - make_file_label (finfo->fullname, use_rev1, - vers ? vers->srcfile : NULL); - } - - if (!have_rev2_label) - { - if (empty_file == DIFF_REMOVED) - label2 = - make_file_label (DEVNULL, NULL, NULL); - else - label2 = - make_file_label (finfo->fullname, use_rev2, - vers ? vers->srcfile : NULL); - } - - if (empty_file == DIFF_ADDED || empty_file == DIFF_REMOVED) - { - /* This is fullname, not file, possibly despite the POSIX.2 - * specification, because that's the way all the Larry Wall - * implementations of patch (are there other implementations?) want - * things and the POSIX.2 spec appears to leave room for this. - */ - cvs_output ("\ -===================================================================\n\ -RCS file: ", 0); - cvs_output (finfo->fullname, 0); - cvs_output ("\n", 1); - - cvs_output ("diff -N ", 0); - cvs_output (finfo->fullname, 0); - cvs_output ("\n", 1); - - if (empty_file == DIFF_ADDED) - { - if (use_rev2 == NULL) - status = diff_exec (DEVNULL, finfo->file, label1, label2, - diff_argc, diff_argv, RUN_TTY); - else - { - int retcode; - - tmp = cvs_temp_name (); - retcode = RCS_checkout (vers->srcfile, (char *) NULL, - use_rev2, (char *) NULL, - (*options - ? options - : vers->options), - tmp, (RCSCHECKOUTPROC) NULL, - (void *) NULL); - if( retcode != 0 ) - goto out; - - status = diff_exec (DEVNULL, tmp, label1, label2, - diff_argc, diff_argv, RUN_TTY); - } - } - else - { - int retcode; - - tmp = cvs_temp_name (); - retcode = RCS_checkout (vers->srcfile, (char *) NULL, - use_rev1, (char *) NULL, - *options ? options : vers->options, - tmp, (RCSCHECKOUTPROC) NULL, - (void *) NULL); - if (retcode != 0) - goto out; - - status = diff_exec (tmp, DEVNULL, label1, label2, - diff_argc, diff_argv, RUN_TTY); - } - } - else - { - status = RCS_exec_rcsdiff (vers->srcfile, diff_argc, diff_argv, - *options ? options : vers->options, - use_rev1, rev1_cache, use_rev2, - label1, label2, finfo->file); - - } - - if (label1) free (label1); - if (label2) free (label2); - - switch (status) - { - case -1: /* fork failed */ - error (1, errno, "fork failed while diffing %s", - vers->srcfile->path); - case 0: /* everything ok */ - err = 0; - break; - default: /* other error */ - err = status; - break; - } - -out: - if( tocvsPath != NULL ) - { - if (unlink_file_dir (finfo->file) < 0) - if (! existence_error (errno)) - error (1, errno, "cannot remove %s", finfo->file); - - rename_file (fname, finfo->file); - if (unlink_file (tocvsPath) < 0) - error (1, errno, "cannot remove %s", tocvsPath); - free (fname); - } - - /* Call CVS_UNLINK() rather than unlink_file() below to avoid the check - * for noexec. - */ - if( tmp != NULL ) - { - if (CVS_UNLINK(tmp) < 0) - error (0, errno, "cannot remove %s", tmp); - free (tmp); - } - if( rev1_cache != NULL ) - { - if( CVS_UNLINK( rev1_cache ) < 0 ) - error( 0, errno, "cannot remove %s", rev1_cache ); - free( rev1_cache ); - } - - freevers_ts (&vers); - diff_mark_errors (err); - return err; -} - -/* - * Remember the exit status for each file. - */ -static void -diff_mark_errors (err) - int err; -{ - if (err > diff_errors) - diff_errors = err; -} - -/* - * Print a warm fuzzy message when we enter a dir - * - * Don't try to diff directories that don't exist! -- DW - */ -/* ARGSUSED */ -static Dtype -diff_dirproc (callerdat, dir, pos_repos, update_dir, entries) - void *callerdat; - const char *dir; - const char *pos_repos; - const char *update_dir; - List *entries; -{ - /* XXX - check for dirs we don't want to process??? */ - - /* YES ... for instance dirs that don't exist!!! -- DW */ - if (!isdir (dir)) - return (R_SKIP_ALL); - - if (!quiet) - error (0, 0, "Diffing %s", update_dir); - return (R_PROCESS); -} - -/* - * Concoct the proper exit status - done with files - */ -/* ARGSUSED */ -static int -diff_filesdoneproc (callerdat, err, repos, update_dir, entries) - void *callerdat; - int err; - const char *repos; - const char *update_dir; - List *entries; -{ - return (diff_errors); -} - -/* - * Concoct the proper exit status - leaving directories - */ -/* ARGSUSED */ -static int -diff_dirleaveproc (callerdat, dir, err, update_dir, entries) - void *callerdat; - const char *dir; - int err; - const char *update_dir; - List *entries; -{ - return (diff_errors); -} - -/* - * verify that a file is different - */ -static enum diff_file -diff_file_nodiff( finfo, vers, empty_file, rev1_cache ) - struct file_info *finfo; - Vers_TS *vers; - enum diff_file empty_file; - char **rev1_cache; /* Cache the content of rev1 if we have to look - * it up. - */ -{ - Vers_TS *xvers; - int retcode; - - /* free up any old use_rev* variables and reset 'em */ - if (use_rev1) - free (use_rev1); - if (use_rev2) - free (use_rev2); - use_rev1 = use_rev2 = (char *) NULL; - - if (diff_rev1 || diff_date1) - { - /* special handling for TAG_HEAD */ - if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0) - { - if (vers->vn_rcs != NULL && vers->srcfile != NULL) - use_rev1 = RCS_branch_head (vers->srcfile, vers->vn_rcs); - } - else - { - xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0); - if (xvers->vn_rcs != NULL) - use_rev1 = xstrdup (xvers->vn_rcs); - freevers_ts (&xvers); - } - } - if (diff_rev2 || diff_date2) - { - /* special handling for TAG_HEAD */ - if (diff_rev2 && strcmp (diff_rev2, TAG_HEAD) == 0) - { - if (vers->vn_rcs != NULL && vers->srcfile != NULL) - use_rev2 = RCS_branch_head (vers->srcfile, vers->vn_rcs); - } - else - { - xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0); - if (xvers->vn_rcs != NULL) - use_rev2 = xstrdup (xvers->vn_rcs); - freevers_ts (&xvers); - } - - if( use_rev1 == NULL || RCS_isdead( vers->srcfile, use_rev1 ) ) - { - /* The first revision does not exist. If EMPTY_FILES is - true, treat this as an added file. Otherwise, warn - about the missing tag. */ - if( use_rev2 == NULL || RCS_isdead( vers->srcfile, use_rev2 ) ) - /* At least in the case where DIFF_REV1 and DIFF_REV2 - * are both numeric (and non-existant (NULL), as opposed to - * dead?), we should be returning some kind of error (see - * basicb-8a0 in testsuite). The symbolic case may be more - * complicated. - */ - return DIFF_SAME; - if( empty_files ) - return DIFF_ADDED; - if( use_rev1 != NULL ) - { - if (diff_rev1) - { - error( 0, 0, - "Tag %s refers to a dead (removed) revision in file `%s'.", - diff_rev1, finfo->fullname ); - } - else - { - error( 0, 0, - "Date %s refers to a dead (removed) revision in file `%s'.", - diff_date1, finfo->fullname ); - } - error( 0, 0, - "No comparison available. Pass `-N' to `%s diff'?", - program_name ); - } - else if (diff_rev1) - error (0, 0, "tag %s is not in file %s", diff_rev1, - finfo->fullname); - else - error (0, 0, "no revision for date %s in file %s", - diff_date1, finfo->fullname); - return DIFF_ERROR; - } - - assert( use_rev1 != NULL ); - if( use_rev2 == NULL || RCS_isdead( vers->srcfile, use_rev2 ) ) - { - /* The second revision does not exist. If EMPTY_FILES is - true, treat this as a removed file. Otherwise warn - about the missing tag. */ - if (empty_files) - return DIFF_REMOVED; - if( use_rev2 != NULL ) - { - if (diff_rev2) - { - error( 0, 0, - "Tag %s refers to a dead (removed) revision in file `%s'.", - diff_rev2, finfo->fullname ); - } - else - { - error( 0, 0, - "Date %s refers to a dead (removed) revision in file `%s'.", - diff_date2, finfo->fullname ); - } - error( 0, 0, - "No comparison available. Pass `-N' to `%s diff'?", - program_name ); - } - else if (diff_rev2) - error (0, 0, "tag %s is not in file %s", diff_rev2, - finfo->fullname); - else - error (0, 0, "no revision for date %s in file %s", - diff_date2, finfo->fullname); - return DIFF_ERROR; - } - /* Now, see if we really need to do the diff. We can't assume that the - * files are different when the revs are. - */ - assert( use_rev2 != NULL ); - if( strcmp (use_rev1, use_rev2) == 0 ) - return DIFF_SAME; - /* else fall through and do the diff */ - } - - /* If we had a r1/d1 & r2/d2, then at this point we must have a C3P0... - * err... ok, then both rev1 & rev2 must have resolved to an existing, - * live version due to if statement we just closed. - */ - assert (!(diff_rev2 || diff_date2) || (use_rev1 && use_rev2)); - - if ((diff_rev1 || diff_date1) && - (use_rev1 == NULL || RCS_isdead (vers->srcfile, use_rev1))) - { - /* The first revision does not exist, and no second revision - was given. */ - if (empty_files) - { - if (empty_file == DIFF_REMOVED) - return DIFF_SAME; - if( user_file_rev && use_rev2 == NULL ) - use_rev2 = xstrdup( user_file_rev ); - return DIFF_ADDED; - } - if( use_rev1 != NULL ) - { - if (diff_rev1) - { - error( 0, 0, - "Tag %s refers to a dead (removed) revision in file `%s'.", - diff_rev1, finfo->fullname ); - } - else - { - error( 0, 0, - "Date %s refers to a dead (removed) revision in file `%s'.", - diff_date1, finfo->fullname ); - } - error( 0, 0, - "No comparison available. Pass `-N' to `%s diff'?", - program_name ); - } - else if ( diff_rev1 ) - error( 0, 0, "tag %s is not in file %s", diff_rev1, - finfo->fullname ); - else - error( 0, 0, "no revision for date %s in file %s", - diff_date1, finfo->fullname ); - return DIFF_ERROR; - } - - assert( !diff_rev1 || use_rev1 ); - - if (user_file_rev) - { - /* drop user_file_rev into first unused use_rev */ - if (!use_rev1) - use_rev1 = xstrdup (user_file_rev); - else if (!use_rev2) - use_rev2 = xstrdup (user_file_rev); - /* and if not, it wasn't needed anyhow */ - user_file_rev = NULL; - } - - /* Now, see if we really need to do the diff. We can't assume that the - * files are different when the revs are. - */ - if( use_rev1 && use_rev2) - { - if (strcmp (use_rev1, use_rev2) == 0) - return DIFF_SAME; - /* Fall through and do the diff. */ - } - /* Don't want to do the timestamp check with both use_rev1 & use_rev2 set. - * The timestamp check is just for the default case of diffing the - * workspace file against its base revision. - */ - else if( use_rev1 == NULL - || ( vers->vn_user != NULL - && strcmp( use_rev1, vers->vn_user ) == 0 ) ) - { - if (empty_file == DIFF_DIFFERENT - && vers->ts_user != NULL - && strcmp (vers->ts_rcs, vers->ts_user) == 0 - && (!(*options) || strcmp (options, vers->options) == 0)) - { - return DIFF_SAME; - } - if (use_rev1 == NULL - && (vers->vn_user[0] != '0' || vers->vn_user[1] != '\0')) - { - if (vers->vn_user[0] == '-') - use_rev1 = xstrdup (vers->vn_user + 1); - else - use_rev1 = xstrdup (vers->vn_user); - } - } - - /* If we already know that the file is being added or removed, - then we don't want to do an actual file comparison here. */ - if (empty_file != DIFF_DIFFERENT) - return empty_file; - - /* - * Run a quick cmp to see if we should bother with a full diff. - */ - - retcode = RCS_cmp_file( vers->srcfile, use_rev1, rev1_cache, - use_rev2, *options ? options : vers->options, - finfo->file ); - - return retcode == 0 ? DIFF_SAME : DIFF_DIFFERENT; -} diff --git a/contrib/cvs/src/edit.c b/contrib/cvs/src/edit.c deleted file mode 100644 index 4e0cf1e..0000000 --- a/contrib/cvs/src/edit.c +++ /dev/null @@ -1,1164 +0,0 @@ -/* Implementation for "cvs edit", "cvs watch on", and related commands - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -#include "cvs.h" -#include "getline.h" -#include "watch.h" -#include "edit.h" -#include "fileattr.h" - -static int watch_onoff PROTO ((int, char **)); - -static int setting_default; -static int turning_on; - -static int setting_tedit; -static int setting_tunedit; -static int setting_tcommit; - -static int onoff_fileproc PROTO ((void *callerdat, struct file_info *finfo)); - -static int -onoff_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - char *watched = fileattr_get0 (finfo->file, "_watched"); - fileattr_set (finfo->file, "_watched", turning_on ? "" : NULL); - if (watched != NULL) - free (watched); - return 0; -} - - - -static int onoff_filesdoneproc PROTO ((void *, int, const char *, const char *, - List *)); - -static int -onoff_filesdoneproc (callerdat, err, repository, update_dir, entries) - void *callerdat; - int err; - const char *repository; - const char *update_dir; - List *entries; -{ - if (setting_default) - { - char *watched = fileattr_get0 (NULL, "_watched"); - fileattr_set (NULL, "_watched", turning_on ? "" : NULL); - if (watched != NULL) - free (watched); - } - return err; -} - -static int -watch_onoff (argc, argv) - int argc; - char **argv; -{ - int c; - int local = 0; - int err; - - optind = 0; - while ((c = getopt (argc, argv, "+lR")) != -1) - { - switch (c) - { - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case '?': - default: - usage (watch_usage); - break; - } - } - argc -= optind; - argv += optind; - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - start_server (); - - ign_setup (); - - if (local) - send_arg ("-l"); - send_arg ("--"); - send_files (argc, argv, local, 0, SEND_NO_CONTENTS); - send_file_names (argc, argv, SEND_EXPAND_WILD); - send_to_server (turning_on ? "watch-on\012" : "watch-off\012", 0); - return get_responses_and_close (); - } -#endif /* CLIENT_SUPPORT */ - - setting_default = (argc <= 0); - - lock_tree_for_write (argc, argv, local, W_LOCAL, 0); - - err = start_recursion (onoff_fileproc, onoff_filesdoneproc, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc, argv, local, W_LOCAL, 0, CVS_LOCK_NONE, - (char *) NULL, 0, (char *) NULL); - - Lock_Cleanup (); - return err; -} - -int -watch_on (argc, argv) - int argc; - char **argv; -{ - turning_on = 1; - return watch_onoff (argc, argv); -} - -int -watch_off (argc, argv) - int argc; - char **argv; -{ - turning_on = 0; - return watch_onoff (argc, argv); -} - -static int dummy_fileproc PROTO ((void *callerdat, struct file_info *finfo)); - -static int -dummy_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - /* This is a pretty hideous hack, but the gist of it is that recurse.c - won't call cvs_notify_check unless there is a fileproc, so we - can't just pass NULL for fileproc. */ - return 0; -} - -static int ncheck_fileproc PROTO ((void *callerdat, struct file_info *finfo)); - -/* Check for and process notifications. Local only. I think that doing - this as a fileproc is the only way to catch all the - cases (e.g. foo/bar.c), even though that means checking over and over - for the same CVSADM_NOTIFY file which we removed the first time we - processed the directory. */ - -static int -ncheck_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - int notif_type; - char *filename; - char *val; - char *cp; - char *watches; - - FILE *fp; - char *line = NULL; - size_t line_len = 0; - - /* We send notifications even if noexec. I'm not sure which behavior - is most sensible. */ - - fp = CVS_FOPEN (CVSADM_NOTIFY, "r"); - if (fp == NULL) - { - if (!existence_error (errno)) - error (0, errno, "cannot open %s", CVSADM_NOTIFY); - return 0; - } - - while (getline (&line, &line_len, fp) > 0) - { - notif_type = line[0]; - if (notif_type == '\0') - continue; - filename = line + 1; - cp = strchr (filename, '\t'); - if (cp == NULL) - continue; - *cp++ = '\0'; - val = cp; - cp = strchr (val, '\t'); - if (cp == NULL) - continue; - *cp++ = '+'; - cp = strchr (cp, '\t'); - if (cp == NULL) - continue; - *cp++ = '+'; - cp = strchr (cp, '\t'); - if (cp == NULL) - continue; - *cp++ = '\0'; - watches = cp; - cp = strchr (cp, '\n'); - if (cp == NULL) - continue; - *cp = '\0'; - - notify_do (notif_type, filename, getcaller (), val, watches, - finfo->repository); - } - free (line); - - if (ferror (fp)) - error (0, errno, "cannot read %s", CVSADM_NOTIFY); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", CVSADM_NOTIFY); - - if ( CVS_UNLINK (CVSADM_NOTIFY) < 0) - error (0, errno, "cannot remove %s", CVSADM_NOTIFY); - - return 0; -} - -static int send_notifications PROTO ((int, char **, int)); - -/* Look through the CVSADM_NOTIFY file and process each item there - accordingly. */ -static int -send_notifications (argc, argv, local) - int argc; - char **argv; - int local; -{ - int err = 0; - -#ifdef CLIENT_SUPPORT - /* OK, we've done everything which needs to happen on the client side. - Now we can try to contact the server; if we fail, then the - notifications stay in CVSADM_NOTIFY to be sent next time. */ - if (current_parsed_root->isremote) - { - if (strcmp (cvs_cmd_name, "release") != 0) - { - start_server (); - ign_setup (); - } - - err += start_recursion (dummy_fileproc, (FILESDONEPROC) NULL, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc, argv, local, W_LOCAL, 0, 0, (char *)NULL, - 0, (char *) NULL); - - send_to_server ("noop\012", 0); - if (strcmp (cvs_cmd_name, "release") == 0) - err += get_server_responses (); - else - err += get_responses_and_close (); - } - else -#endif - { - /* Local. */ - - lock_tree_for_write (argc, argv, local, W_LOCAL, 0); - err += start_recursion (ncheck_fileproc, (FILESDONEPROC) NULL, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc, argv, local, W_LOCAL, 0, 0, (char *)NULL, - 0, (char *) NULL); - Lock_Cleanup (); - } - return err; -} - -static int edit_fileproc PROTO ((void *callerdat, struct file_info *finfo)); - -static int -edit_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - FILE *fp; - time_t now; - char *ascnow; - char *basefilename; - - if (noexec) - return 0; - - /* This is a somewhat screwy way to check for this, because it - doesn't help errors other than the nonexistence of the file - (e.g. permissions problems). It might be better to rearrange - the code so that CVSADM_NOTIFY gets written only after the - various actions succeed (but what if only some of them - succeed). */ - if (!isfile (finfo->file)) - { - error (0, 0, "no such file %s; ignored", finfo->fullname); - return 0; - } - - fp = open_file (CVSADM_NOTIFY, "a"); - - (void) time (&now); - ascnow = asctime (gmtime (&now)); - ascnow[24] = '\0'; - /* Fix non-standard format. */ - if (ascnow[8] == '0') ascnow[8] = ' '; - fprintf (fp, "E%s\t%s GMT\t%s\t%s\t", finfo->file, - ascnow, hostname, CurDir); - if (setting_tedit) - fprintf (fp, "E"); - if (setting_tunedit) - fprintf (fp, "U"); - if (setting_tcommit) - fprintf (fp, "C"); - fprintf (fp, "\n"); - - if (fclose (fp) < 0) - { - if (finfo->update_dir[0] == '\0') - error (0, errno, "cannot close %s", CVSADM_NOTIFY); - else - error (0, errno, "cannot close %s/%s", finfo->update_dir, - CVSADM_NOTIFY); - } - - xchmod (finfo->file, 1); - - /* Now stash the file away in CVSADM so that unedit can revert even if - it can't communicate with the server. We stash away a writable - copy so that if the user removes the working file, then restores it - with "cvs update" (which clears _editors but does not update - CVSADM_BASE), then a future "cvs edit" can still win. */ - /* Could save a system call by only calling mkdir_if_needed if - trying to create the output file fails. But copy_file isn't - set up to facilitate that. */ - mkdir_if_needed (CVSADM_BASE); - basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (finfo->file)); - strcpy (basefilename, CVSADM_BASE); - strcat (basefilename, "/"); - strcat (basefilename, finfo->file); - copy_file (finfo->file, basefilename); - free (basefilename); - - { - Node *node; - - node = findnode_fn (finfo->entries, finfo->file); - if (node != NULL) - base_register (finfo, ((Entnode *) node->data)->version); - } - - return 0; -} - -static const char *const edit_usage[] = -{ - "Usage: %s %s [-lR] [-a <action>]... [<file>]...\n", - "-l\tLocal directory only, not recursive.\n", - "-R\tProcess directories recursively (default).\n", - "-a\tSpecify action to register for temporary watch, one of:\n", - " \t`edit', `unedit', `commit', `all', or `none' (defaults to `all').\n", - "(Specify the --help global option for a list of other help options.)\n", - NULL -}; - -int -edit (argc, argv) - int argc; - char **argv; -{ - int local = 0; - int c; - int err; - int a_omitted; - - if (argc == -1) - usage (edit_usage); - - a_omitted = 1; - setting_tedit = 0; - setting_tunedit = 0; - setting_tcommit = 0; - optind = 0; - while ((c = getopt (argc, argv, "+lRa:")) != -1) - { - switch (c) - { - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'a': - a_omitted = 0; - if (strcmp (optarg, "edit") == 0) - setting_tedit = 1; - else if (strcmp (optarg, "unedit") == 0) - setting_tunedit = 1; - else if (strcmp (optarg, "commit") == 0) - setting_tcommit = 1; - else if (strcmp (optarg, "all") == 0) - { - setting_tedit = 1; - setting_tunedit = 1; - setting_tcommit = 1; - } - else if (strcmp (optarg, "none") == 0) - { - setting_tedit = 0; - setting_tunedit = 0; - setting_tcommit = 0; - } - else - usage (edit_usage); - break; - case '?': - default: - usage (edit_usage); - break; - } - } - argc -= optind; - argv += optind; - - if (a_omitted) - { - setting_tedit = 1; - setting_tunedit = 1; - 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, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc, argv, local, W_LOCAL, 0, 0, (char *) NULL, - 0, (char *) NULL); - - err += send_notifications (argc, argv, local); - - return err; -} - -static int unedit_fileproc PROTO ((void *callerdat, struct file_info *finfo)); - -static int -unedit_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - FILE *fp; - time_t now; - char *ascnow; - char *basefilename; - - if (noexec) - return 0; - - basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (finfo->file)); - strcpy (basefilename, CVSADM_BASE); - strcat (basefilename, "/"); - strcat (basefilename, finfo->file); - if (!isfile (basefilename)) - { - /* This file apparently was never cvs edit'd (e.g. we are uneditting - a directory where only some of the files were cvs edit'd. */ - free (basefilename); - return 0; - } - - if (xcmp (finfo->file, basefilename) != 0) - { - printf ("%s has been modified; revert changes? ", finfo->fullname); - if (!yesno ()) - { - /* "no". */ - free (basefilename); - return 0; - } - } - rename_file (basefilename, finfo->file); - free (basefilename); - - fp = open_file (CVSADM_NOTIFY, "a"); - - (void) time (&now); - ascnow = asctime (gmtime (&now)); - ascnow[24] = '\0'; - /* Fix non-standard format. */ - if (ascnow[8] == '0') ascnow[8] = ' '; - fprintf (fp, "U%s\t%s GMT\t%s\t%s\t\n", finfo->file, - ascnow, hostname, CurDir); - - if (fclose (fp) < 0) - { - if (finfo->update_dir[0] == '\0') - error (0, errno, "cannot close %s", CVSADM_NOTIFY); - else - error (0, errno, "cannot close %s/%s", finfo->update_dir, - CVSADM_NOTIFY); - } - - /* Now update the revision number in CVS/Entries from CVS/Baserev. - The basic idea here is that we are reverting to the revision - that the user edited. If we wanted "cvs update" to update - CVS/Base as we go along (so that an unedit could revert to the - current repository revision), we would need: - - update (or all send_files?) (client) needs to send revision in - new Entry-base request. update (server/local) needs to check - revision against repository and send new Update-base response - (like Update-existing in that the file already exists. While - we are at it, might try to clean up the syntax by having the - mode only in a "Mode" response, not in the Update-base itself). */ - { - char *baserev; - Node *node; - Entnode *entdata; - - baserev = base_get (finfo); - node = findnode_fn (finfo->entries, finfo->file); - /* The case where node is NULL probably should be an error or - something, but I don't want to think about it too hard right - now. */ - if (node != NULL) - { - entdata = node->data; - if (baserev == NULL) - { - /* This can only happen if the CVS/Baserev file got - corrupted. We suspect it might be possible if the - user interrupts CVS, although I haven't verified - that. */ - error (0, 0, "%s not mentioned in %s", finfo->fullname, - CVSADM_BASEREV); - - /* Since we don't know what revision the file derives from, - keeping it around would be asking for trouble. */ - if (unlink_file (finfo->file) < 0) - error (0, errno, "cannot remove %s", finfo->fullname); - - /* This is cheesy, in a sense; why shouldn't we do the - update for the user? However, doing that would require - contacting the server, so maybe this is OK. */ - error (0, 0, "run update to complete the unedit"); - return 0; - } - Register (finfo->entries, finfo->file, baserev, entdata->timestamp, - entdata->options, entdata->tag, entdata->date, - entdata->conflict); - } - free (baserev); - base_deregister (finfo); - } - - xchmod (finfo->file, 0); - return 0; -} - -static const char *const unedit_usage[] = -{ - "Usage: %s %s [-lR] [<file>]...\n", - "-l\tLocal directory only, not recursive.\n", - "-R\tProcess directories recursively (default).\n", - "(Specify the --help global option for a list of other help options.)\n", - NULL -}; - -int -unedit (argc, argv) - int argc; - char **argv; -{ - int local = 0; - int c; - int err; - - if (argc == -1) - usage (unedit_usage); - - optind = 0; - while ((c = getopt (argc, argv, "+lR")) != -1) - { - switch (c) - { - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case '?': - default: - usage (unedit_usage); - break; - } - } - argc -= optind; - argv += optind; - - /* No need to readlock since we aren't doing anything to the - repository. */ - err = start_recursion (unedit_fileproc, (FILESDONEPROC) NULL, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc, argv, local, W_LOCAL, 0, 0, (char *)NULL, - 0, (char *) NULL); - - err += send_notifications (argc, argv, local); - - return err; -} - -void -mark_up_to_date (file) - const char *file; -{ - char *base; - - /* The file is up to date, so we better get rid of an out of - date file in CVSADM_BASE. */ - base = xmalloc (strlen (file) + 80); - strcpy (base, CVSADM_BASE); - strcat (base, "/"); - strcat (base, file); - if (unlink_file (base) < 0 && ! existence_error (errno)) - error (0, errno, "cannot remove %s", file); - free (base); -} - - - -void -editor_set (filename, editor, val) - const char *filename; - const char *editor; - const char *val; -{ - char *edlist; - char *newlist; - - edlist = fileattr_get0 (filename, "_editors"); - newlist = fileattr_modify (edlist, editor, val, '>', ','); - /* If the attributes is unchanged, don't rewrite the attribute file. */ - if (!((edlist == NULL && newlist == NULL) - || (edlist != NULL - && newlist != NULL - && strcmp (edlist, newlist) == 0))) - fileattr_set (filename, "_editors", newlist); - if (edlist != NULL) - free (edlist); - if (newlist != NULL) - free (newlist); -} - -struct notify_proc_args { - /* What kind of notification, "edit", "tedit", etc. */ - const char *type; - /* User who is running the command which causes notification. */ - const char *who; - /* User to be notified. */ - const char *notifyee; - /* File. */ - const char *file; -}; - - - -/* Pass as a static until we get around to fixing Parse_Info to pass along - a void * where we can stash it. */ -static struct notify_proc_args *notify_args; - - - -static int notify_proc PROTO ((const char *repository, const char *filter)); - -static int -notify_proc (repository, filter) - const char *repository; - const char *filter; -{ - FILE *pipefp; - char *prog; - char *expanded_prog; - const char *p; - char *q; - const char *srepos; - struct notify_proc_args *args = notify_args; - - srepos = Short_Repository (repository); - prog = xmalloc (strlen (filter) + strlen (args->notifyee) + 1); - /* Copy FILTER to PROG, replacing the first occurrence of %s with - the notifyee. We only allocated enough memory for one %s, and I doubt - there is a need for more. */ - for (p = filter, q = prog; *p != '\0'; ++p) - { - if (p[0] == '%') - { - if (p[1] == 's') - { - strcpy (q, args->notifyee); - q += strlen (q); - strcpy (q, p + 2); - q += strlen (q); - break; - } - else - continue; - } - *q++ = *p; - } - *q = '\0'; - - /* FIXME: why are we calling expand_proc? Didn't we already - expand it in Parse_Info, before passing it to notify_proc? */ - expanded_prog = expand_path (prog, "notify", 0); - if (!expanded_prog) - { - free (prog); - return 1; - } - - pipefp = run_popen (expanded_prog, "w"); - if (pipefp == NULL) - { - error (0, errno, "cannot write entry to notify filter: %s", prog); - free (prog); - free (expanded_prog); - return 1; - } - - fprintf (pipefp, "%s %s\n---\n", srepos, args->file); - fprintf (pipefp, "Triggered %s watch on %s\n", args->type, repository); - fprintf (pipefp, "By %s\n", args->who); - - /* Lots more potentially useful information we could add here; see - logfile_write for inspiration. */ - - free (prog); - free (expanded_prog); - return (pclose (pipefp)); -} - -/* FIXME: this function should have a way to report whether there was - an error so that server.c can know whether to report Notified back - to the client. */ -void -notify_do (type, filename, who, val, watches, repository) - int type; - const char *filename; - const char *who; - const char *val; - const char *watches; - const char *repository; -{ - static struct addremove_args blank; - struct addremove_args args; - char *watchers; - char *p; - char *endp; - char *nextp; - - /* Initialize fields to 0, NULL, or 0.0. */ - args = blank; - switch (type) - { - case 'E': - if (strpbrk (val, ",>;=\n") != NULL) - { - error (0, 0, "invalid character in editor value"); - return; - } - editor_set (filename, who, val); - break; - case 'U': - case 'C': - editor_set (filename, who, NULL); - break; - default: - return; - } - - watchers = fileattr_get0 (filename, "_watchers"); - p = watchers; - while (p != NULL) - { - char *q; - char *endq; - char *nextq; - char *notif; - - endp = strchr (p, '>'); - if (endp == NULL) - break; - nextp = strchr (p, ','); - - if ((size_t)(endp - p) == strlen (who) && strncmp (who, p, endp - p) == 0) - { - /* Don't notify user of their own changes. Would perhaps - be better to check whether it is the same working - directory, not the same user, but that is hairy. */ - p = nextp == NULL ? nextp : nextp + 1; - continue; - } - - /* Now we point q at a string which looks like - "edit+unedit+commit,"... and walk down it. */ - q = endp + 1; - notif = NULL; - while (q != NULL) - { - endq = strchr (q, '+'); - if (endq == NULL || (nextp != NULL && endq > nextp)) - { - if (nextp == NULL) - endq = q + strlen (q); - else - endq = nextp; - nextq = NULL; - } - else - nextq = endq + 1; - - /* If there is a temporary and a regular watch, send a single - notification, for the regular watch. */ - if (type == 'E' && endq - q == 4 && strncmp ("edit", q, 4) == 0) - { - notif = "edit"; - } - else if (type == 'U' - && endq - q == 6 && strncmp ("unedit", q, 6) == 0) - { - notif = "unedit"; - } - else if (type == 'C' - && endq - q == 6 && strncmp ("commit", q, 6) == 0) - { - notif = "commit"; - } - else if (type == 'E' - && endq - q == 5 && strncmp ("tedit", q, 5) == 0) - { - if (notif == NULL) - notif = "temporary edit"; - } - else if (type == 'U' - && endq - q == 7 && strncmp ("tunedit", q, 7) == 0) - { - if (notif == NULL) - notif = "temporary unedit"; - } - else if (type == 'C' - && endq - q == 7 && strncmp ("tcommit", q, 7) == 0) - { - if (notif == NULL) - notif = "temporary commit"; - } - q = nextq; - } - if (nextp != NULL) - ++nextp; - - if (notif != NULL) - { - struct notify_proc_args args; - size_t len = endp - p; - FILE *fp; - char *usersname; - char *line = NULL; - size_t line_len = 0; - - args.notifyee = NULL; - usersname = xmalloc (strlen (current_parsed_root->directory) - + sizeof CVSROOTADM - + sizeof CVSROOTADM_USERS - + 20); - strcpy (usersname, current_parsed_root->directory); - strcat (usersname, "/"); - strcat (usersname, CVSROOTADM); - strcat (usersname, "/"); - strcat (usersname, CVSROOTADM_USERS); - fp = CVS_FOPEN (usersname, "r"); - if (fp == NULL && !existence_error (errno)) - error (0, errno, "cannot read %s", usersname); - if (fp != NULL) - { - while (getline (&line, &line_len, fp) >= 0) - { - if (strncmp (line, p, len) == 0 - && line[len] == ':') - { - char *cp; - args.notifyee = xstrdup (line + len + 1); - - /* There may or may not be more - colon-separated fields added to this in the - future; in any case, we ignore them right - now, and if there are none we make sure to - chop off the final newline, if any. */ - cp = strpbrk (args.notifyee, ":\n"); - - if (cp != NULL) - *cp = '\0'; - break; - } - } - if (ferror (fp)) - error (0, errno, "cannot read %s", usersname); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", usersname); - } - free (usersname); - if (line != NULL) - free (line); - - if (args.notifyee == NULL) - { - char *tmp; - tmp = xmalloc (endp - p + 1); - strncpy (tmp, p, endp - p); - tmp[endp - p] = '\0'; - args.notifyee = tmp; - } - - notify_args = &args; - args.type = notif; - args.who = who; - args.file = filename; - - (void) Parse_Info (CVSROOTADM_NOTIFY, repository, notify_proc, 1); - - /* It's okay to cast out the const for the free() below since we - * just allocated this a few lines above. The const was for - * everybody else. - */ - free ((char *)args.notifyee); - } - - p = nextp; - } - if (watchers != NULL) - free (watchers); - - switch (type) - { - case 'E': - if (*watches == 'E') - { - args.add_tedit = 1; - ++watches; - } - if (*watches == 'U') - { - args.add_tunedit = 1; - ++watches; - } - if (*watches == 'C') - { - args.add_tcommit = 1; - } - watch_modify_watchers (filename, &args); - break; - case 'U': - case 'C': - args.remove_temp = 1; - watch_modify_watchers (filename, &args); - break; - } -} - -#ifdef CLIENT_SUPPORT -/* Check and send notifications. This is only for the client. */ -void -cvs_notify_check (repository, update_dir) - const char *repository; - const char *update_dir; -{ - FILE *fp; - char *line = NULL; - size_t line_len = 0; - - if (! server_started) - /* We are in the midst of a command which is not to talk to - the server (e.g. the first phase of a cvs edit). Just chill - out, we'll catch the notifications on the flip side. */ - return; - - /* We send notifications even if noexec. I'm not sure which behavior - is most sensible. */ - - fp = CVS_FOPEN (CVSADM_NOTIFY, "r"); - if (fp == NULL) - { - if (!existence_error (errno)) - error (0, errno, "cannot open %s", CVSADM_NOTIFY); - return; - } - while (getline (&line, &line_len, fp) > 0) - { - int notif_type; - char *filename; - char *val; - char *cp; - - notif_type = line[0]; - if (notif_type == '\0') - continue; - filename = line + 1; - cp = strchr (filename, '\t'); - if (cp == NULL) - continue; - *cp++ = '\0'; - val = cp; - - client_notify (repository, update_dir, filename, notif_type, val); - } - if (line) - free (line); - if (ferror (fp)) - error (0, errno, "cannot read %s", CVSADM_NOTIFY); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", CVSADM_NOTIFY); - - /* Leave the CVSADM_NOTIFY file there, until the server tells us it - has dealt with it. */ -} -#endif /* CLIENT_SUPPORT */ - - -static const char *const editors_usage[] = -{ - "Usage: %s %s [-lR] [<file>]...\n", - "-l\tProcess this directory only (not recursive).\n", - "-R\tProcess directories recursively (default).\n", - "(Specify the --help global option for a list of other help options.)\n", - NULL -}; - -static int editors_fileproc PROTO ((void *callerdat, struct file_info *finfo)); - -static int -editors_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - char *them; - char *p; - - them = fileattr_get0 (finfo->file, "_editors"); - if (them == NULL) - return 0; - - cvs_output (finfo->fullname, 0); - - p = them; - while (1) - { - cvs_output ("\t", 1); - while (*p != '>' && *p != '\0') - cvs_output (p++, 1); - if (*p == '\0') - { - /* Only happens if attribute is misformed. */ - cvs_output ("\n", 1); - break; - } - ++p; - cvs_output ("\t", 1); - while (1) - { - while (*p != '+' && *p != ',' && *p != '\0') - cvs_output (p++, 1); - if (*p == '\0') - { - cvs_output ("\n", 1); - goto out; - } - if (*p == ',') - { - ++p; - break; - } - ++p; - cvs_output ("\t", 1); - } - cvs_output ("\n", 1); - } - out:; - free (them); - return 0; -} - -int -editors (argc, argv) - int argc; - char **argv; -{ - int local = 0; - int c; - - if (argc == -1) - usage (editors_usage); - - optind = 0; - while ((c = getopt (argc, argv, "+lR")) != -1) - { - switch (c) - { - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case '?': - default: - usage (editors_usage); - break; - } - } - argc -= optind; - argv += optind; - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - start_server (); - ign_setup (); - - if (local) - send_arg ("-l"); - send_arg ("--"); - send_files (argc, argv, local, 0, SEND_NO_CONTENTS); - send_file_names (argc, argv, SEND_EXPAND_WILD); - send_to_server ("editors\012", 0); - return get_responses_and_close (); - } -#endif /* CLIENT_SUPPORT */ - - return start_recursion (editors_fileproc, (FILESDONEPROC) NULL, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc, argv, local, W_LOCAL, 0, 1, (char *) NULL, - 0, (char *) NULL); -} diff --git a/contrib/cvs/src/edit.h b/contrib/cvs/src/edit.h deleted file mode 100644 index 9b20180..0000000 --- a/contrib/cvs/src/edit.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Interface to "cvs edit", "cvs watch on", and related features - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -extern int watch_on PROTO ((int argc, char **argv)); -extern int watch_off PROTO ((int argc, char **argv)); - -#ifdef CLIENT_SUPPORT -/* Check to see if any notifications are sitting around in need of being - sent. These are the notifications stored in CVSADM_NOTIFY (edit,unedit); - commit calls notify_do directly. */ -extern void cvs_notify_check PROTO ((const char *repository, - const char *update_dir)); -#endif /* CLIENT_SUPPORT */ - -/* Issue a notification for file FILENAME. TYPE is 'E' for edit, 'U' - for unedit, and 'C' for commit. WHO is the user currently running. - For TYPE 'E', VAL is the time+host+directory data which goes in - _editors, and WATCHES is zero or more of E,U,C, in that order, to specify - what kinds of temporary watches to set. */ -extern void notify_do PROTO ((int type, const char *filename, const char *who, - const char *val, const char *watches, - const char *repository)); - -/* Set attributes to reflect the fact that EDITOR is editing FILENAME. - VAL is time+host+directory, or NULL if we are to say that EDITOR is - *not* editing FILENAME. */ -extern void editor_set PROTO ((const char *filename, const char *editor, - const char *val)); - -/* Take note of the fact that FILE is up to date (this munges CVS/Base; - processing of CVS/Entries is done separately). */ -extern void mark_up_to_date PROTO ((const char *file)); diff --git a/contrib/cvs/src/entries.c b/contrib/cvs/src/entries.c deleted file mode 100644 index 9592c3c..0000000 --- a/contrib/cvs/src/entries.c +++ /dev/null @@ -1,1263 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Entries file to Files file - * - * Creates the file Files containing the names that comprise the project, from - * the Entries file. - */ - -/* - * $FreeBSD$ - */ -#include "cvs.h" -#include "getline.h" - -static Node *AddEntryNode PROTO((List * list, Entnode *entnode)); - -static Entnode *fgetentent PROTO((FILE *, char *, int *)); -static int fputentent PROTO((FILE *, Entnode *)); - -static Entnode *subdir_record PROTO((int, const char *, const char *)); - -static FILE *entfile; -static char *entfilename; /* for error messages */ - - - -/* - * Construct an Entnode - */ -static Entnode *Entnode_Create PROTO ((enum ent_type, const char *, - const char *, const char *, - const char *, const char *, - const char *, const char *)); - -static Entnode * -Entnode_Create(type, user, vn, ts, options, tag, date, ts_conflict) - enum ent_type type; - const char *user; - const char *vn; - const char *ts; - const char *options; - const char *tag; - const char *date; - const char *ts_conflict; -{ - Entnode *ent; - - /* Note that timestamp and options must be non-NULL */ - ent = (Entnode *) xmalloc (sizeof (Entnode)); - ent->type = type; - ent->user = xstrdup (user); - ent->version = xstrdup (vn); - ent->timestamp = xstrdup (ts ? ts : ""); - ent->options = xstrdup (options ? options : ""); - ent->tag = xstrdup (tag); - ent->date = xstrdup (date); - ent->conflict = xstrdup (ts_conflict); - - return ent; -} - -/* - * Destruct an Entnode - */ -static void Entnode_Destroy PROTO ((Entnode *)); - -static void -Entnode_Destroy (ent) - Entnode *ent; -{ - free (ent->user); - free (ent->version); - free (ent->timestamp); - free (ent->options); - if (ent->tag) - free (ent->tag); - if (ent->date) - free (ent->date); - if (ent->conflict) - free (ent->conflict); - free (ent); -} - -/* - * Write out the line associated with a node of an entries file - */ -static int write_ent_proc PROTO ((Node *, void *)); -static int -write_ent_proc (node, closure) - Node *node; - void *closure; -{ - Entnode *entnode = node->data; - - if (closure != NULL && entnode->type != ENT_FILE) - *(int *) closure = 1; - - if (fputentent(entfile, entnode)) - error (1, errno, "cannot write %s", entfilename); - - return (0); -} - -/* - * write out the current entries file given a list, making a backup copy - * first of course - */ -static void -write_entries (list) - List *list; -{ - int sawdir; - - sawdir = 0; - - /* open the new one and walk the list writing entries */ - entfilename = CVSADM_ENTBAK; - entfile = CVS_FOPEN (entfilename, "w+"); - if (entfile == NULL) - { - /* Make this a warning, not an error. For example, one user might - have checked out a working directory which, for whatever reason, - contains an Entries.Log file. A second user, without write access - to that working directory, might want to do a "cvs log". The - problem rewriting Entries shouldn't affect the ability of "cvs log" - to work, although the warning is probably a good idea so that - whether Entries gets rewritten is not an inexplicable process. */ - /* FIXME: should be including update_dir in message. */ - error (0, errno, "cannot rewrite %s", entfilename); - - /* Now just return. We leave the Entries.Log file around. As far - as I know, there is never any data lying around in 'list' that - is not in Entries.Log at this time (if there is an error writing - Entries.Log that is a separate problem). */ - return; - } - - (void) walklist (list, write_ent_proc, (void *) &sawdir); - if (! sawdir) - { - struct stickydirtag *sdtp; - - /* We didn't write out any directories. Check the list - private data to see whether subdirectory information is - known. If it is, we need to write out an empty D line. */ - sdtp = list->list->data; - if (sdtp == NULL || sdtp->subdirs) - if (fprintf (entfile, "D\n") < 0) - error (1, errno, "cannot write %s", entfilename); - } - if (fclose (entfile) == EOF) - error (1, errno, "error closing %s", entfilename); - - /* now, atomically (on systems that support it) rename it */ - rename_file (entfilename, CVSADM_ENT); - - /* now, remove the log file */ - if (unlink_file (CVSADM_ENTLOG) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", CVSADM_ENTLOG); -} - - - -/* - * Removes the argument file from the Entries file if necessary. - */ -void -Scratch_Entry (list, fname) - List *list; - const char *fname; -{ - Node *node; - - if (trace) - (void) fprintf (stderr, "%s-> Scratch_Entry(%s)\n", - CLIENT_SERVER_STR, fname); - - /* hashlookup to see if it is there */ - if ((node = findnode_fn (list, fname)) != NULL) - { - if (!noexec) - { - entfilename = CVSADM_ENTLOG; - entfile = open_file (entfilename, "a"); - - if (fprintf (entfile, "R ") < 0) - error (1, errno, "cannot write %s", entfilename); - - write_ent_proc (node, NULL); - - if (fclose (entfile) == EOF) - error (1, errno, "error closing %s", entfilename); - } - - delnode (node); /* delete the node */ - -#ifdef SERVER_SUPPORT - if (server_active) - server_scratch (fname); -#endif - } -} - - - -/* - * Enters the given file name/version/time-stamp into the Entries file, - * removing the old entry first, if necessary. - */ -void -Register (list, fname, vn, ts, options, tag, date, ts_conflict) - List *list; - const char *fname; - const char *vn; - const char *ts; - const char *options; - const char *tag; - const char *date; - const char *ts_conflict; -{ - Entnode *entnode; - Node *node; - -#ifdef SERVER_SUPPORT - if (server_active) - { - server_register (fname, vn, ts, options, tag, date, ts_conflict); - } -#endif - - if (trace) - { - (void) fprintf (stderr, "%s-> Register(%s, %s, %s%s%s, %s, %s %s)\n", - CLIENT_SERVER_STR, - fname, vn, ts ? ts : "", - ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "", - options, tag ? tag : "", date ? date : ""); - } - - entnode = Entnode_Create (ENT_FILE, fname, vn, ts, options, tag, date, - ts_conflict); - node = AddEntryNode (list, entnode); - - if (!noexec) - { - entfilename = CVSADM_ENTLOG; - entfile = CVS_FOPEN (entfilename, "a"); - - if (entfile == NULL) - { - /* Warning, not error, as in write_entries. */ - /* FIXME-update-dir: should be including update_dir in message. */ - error (0, errno, "cannot open %s", entfilename); - return; - } - - if (fprintf (entfile, "A ") < 0) - error (1, errno, "cannot write %s", entfilename); - - write_ent_proc (node, NULL); - - if (fclose (entfile) == EOF) - error (1, errno, "error closing %s", entfilename); - } -} - -/* - * Node delete procedure for list-private sticky dir tag/date info - */ -static void -freesdt (p) - Node *p; -{ - struct stickydirtag *sdtp = p->data; - - if (sdtp->tag) - free (sdtp->tag); - if (sdtp->date) - free (sdtp->date); - free ((char *) sdtp); -} - -/* Return the next real Entries line. On end of file, returns NULL. - On error, prints an error message and returns NULL. */ - -static Entnode * -fgetentent(fpin, cmd, sawdir) - FILE *fpin; - char *cmd; - int *sawdir; -{ - Entnode *ent; - char *line; - size_t line_chars_allocated; - register char *cp; - enum ent_type type; - char *l, *user, *vn, *ts, *options; - char *tag_or_date, *tag, *date, *ts_conflict; - int line_length; - - line = NULL; - line_chars_allocated = 0; - - ent = NULL; - while ((line_length = getline (&line, &line_chars_allocated, fpin)) > 0) - { - l = line; - - /* If CMD is not NULL, we are reading an Entries.Log file. - Each line in the Entries.Log file starts with a single - character command followed by a space. For backward - compatibility, the absence of a space indicates an add - command. */ - if (cmd != NULL) - { - if (l[1] != ' ') - *cmd = 'A'; - else - { - *cmd = l[0]; - l += 2; - } - } - - type = ENT_FILE; - - if (l[0] == 'D') - { - type = ENT_SUBDIR; - *sawdir = 1; - ++l; - /* An empty D line is permitted; it is a signal that this - Entries file lists all known subdirectories. */ - } - - if (l[0] != '/') - continue; - - user = l + 1; - if ((cp = strchr (user, '/')) == NULL) - continue; - *cp++ = '\0'; - vn = cp; - if ((cp = strchr (vn, '/')) == NULL) - continue; - *cp++ = '\0'; - ts = cp; - if ((cp = strchr (ts, '/')) == NULL) - continue; - *cp++ = '\0'; - options = cp; - if ((cp = strchr (options, '/')) == NULL) - continue; - *cp++ = '\0'; - tag_or_date = cp; - if ((cp = strchr (tag_or_date, '\n')) == NULL) - continue; - *cp = '\0'; - tag = (char *) NULL; - date = (char *) NULL; - if (*tag_or_date == 'T') - tag = tag_or_date + 1; - else if (*tag_or_date == 'D') - date = tag_or_date + 1; - - if ((ts_conflict = strchr (ts, '+'))) - *ts_conflict++ = '\0'; - - /* - * XXX - Convert timestamp from old format to new format. - * - * If the timestamp doesn't match the file's current - * mtime, we'd have to generate a string that doesn't - * match anyways, so cheat and base it on the existing - * string; it doesn't have to match the same mod time. - * - * For an unmodified file, write the correct timestamp. - */ - { - struct stat sb; - if (strlen (ts) > 30 && CVS_STAT (user, &sb) == 0) - { - char *c = ctime (&sb.st_mtime); - /* Fix non-standard format. */ - if (c[8] == '0') c[8] = ' '; - - if (!strncmp (ts + 25, c, 24)) - ts = time_stamp (user); - else - { - ts += 24; - ts[0] = '*'; - } - } - } - - ent = Entnode_Create (type, user, vn, ts, options, tag, date, - ts_conflict); - break; - } - - if (line_length < 0 && !feof (fpin)) - error (0, errno, "cannot read entries file"); - - free (line); - return ent; -} - -static int -fputentent(fp, p) - FILE *fp; - Entnode *p; -{ - switch (p->type) - { - case ENT_FILE: - break; - case ENT_SUBDIR: - if (fprintf (fp, "D") < 0) - return 1; - break; - } - - if (fprintf (fp, "/%s/%s/%s", p->user, p->version, p->timestamp) < 0) - return 1; - if (p->conflict) - { - if (fprintf (fp, "+%s", p->conflict) < 0) - return 1; - } - if (fprintf (fp, "/%s/", p->options) < 0) - return 1; - - if (p->tag) - { - if (fprintf (fp, "T%s\n", p->tag) < 0) - return 1; - } - else if (p->date) - { - if (fprintf (fp, "D%s\n", p->date) < 0) - return 1; - } - else - { - if (fprintf (fp, "\n") < 0) - return 1; - } - - return 0; -} - - -/* Read the entries file into a list, hashing on the file name. - - UPDATE_DIR is the name of the current directory, for use in error - messages, or NULL if not known (that is, noone has gotten around - to updating the caller to pass in the information). */ -List * -Entries_Open (aflag, update_dir) - int aflag; - char *update_dir; -{ - List *entries; - struct stickydirtag *sdtp = NULL; - Entnode *ent; - char *dirtag, *dirdate; - int dirnonbranch; - int do_rewrite = 0; - FILE *fpin; - int sawdir; - - /* get a fresh list... */ - entries = getlist (); - - /* - * Parse the CVS/Tag file, to get any default tag/date settings. Use - * list-private storage to tuck them away for Version_TS(). - */ - ParseTag (&dirtag, &dirdate, &dirnonbranch); - if (aflag || dirtag || dirdate) - { - sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp)); - memset ((char *) sdtp, 0, sizeof (*sdtp)); - sdtp->aflag = aflag; - sdtp->tag = xstrdup (dirtag); - sdtp->date = xstrdup (dirdate); - sdtp->nonbranch = dirnonbranch; - - /* feed it into the list-private area */ - entries->list->data = sdtp; - entries->list->delproc = freesdt; - } - - sawdir = 0; - - fpin = CVS_FOPEN (CVSADM_ENT, "r"); - if (fpin == NULL) - { - if (update_dir != NULL) - error (0, 0, "in directory %s:", update_dir); - error (0, errno, "cannot open %s for reading", CVSADM_ENT); - } - else - { - while ((ent = fgetentent (fpin, (char *) NULL, &sawdir)) != NULL) - { - (void) AddEntryNode (entries, ent); - } - - if (fclose (fpin) < 0) - /* FIXME-update-dir: should include update_dir in message. */ - error (0, errno, "cannot close %s", CVSADM_ENT); - } - - fpin = CVS_FOPEN (CVSADM_ENTLOG, "r"); - if (fpin != NULL) - { - char cmd; - Node *node; - - while ((ent = fgetentent (fpin, &cmd, &sawdir)) != NULL) - { - switch (cmd) - { - case 'A': - (void) AddEntryNode (entries, ent); - break; - case 'R': - node = findnode_fn (entries, ent->user); - if (node != NULL) - delnode (node); - Entnode_Destroy (ent); - break; - default: - /* Ignore unrecognized commands. */ - Entnode_Destroy (ent); - break; - } - } - do_rewrite = 1; - if (fclose (fpin) < 0) - /* FIXME-update-dir: should include update_dir in message. */ - error (0, errno, "cannot close %s", CVSADM_ENTLOG); - } - - /* Update the list private data to indicate whether subdirectory - information is known. Nonexistent list private data is taken - to mean that it is known. */ - if (sdtp != NULL) - sdtp->subdirs = sawdir; - else if (! sawdir) - { - sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp)); - memset ((char *) sdtp, 0, sizeof (*sdtp)); - sdtp->subdirs = 0; - entries->list->data = sdtp; - entries->list->delproc = freesdt; - } - - if (do_rewrite && !noexec) - write_entries (entries); - - /* clean up and return */ - if (dirtag) - free (dirtag); - if (dirdate) - free (dirdate); - return (entries); -} - -void -Entries_Close(list) - List *list; -{ - if (list) - { - if (!noexec) - { - if (isfile (CVSADM_ENTLOG)) - write_entries (list); - } - dellist(&list); - } -} - - -/* - * Free up the memory associated with the data section of an ENTRIES type - * node - */ -static void -Entries_delproc (node) - Node *node; -{ - Entnode *p = node->data; - - Entnode_Destroy(p); -} - -/* - * Get an Entries file list node, initialize it, and add it to the specified - * list - */ -static Node * -AddEntryNode (list, entdata) - List *list; - Entnode *entdata; -{ - Node *p; - - /* was it already there? */ - if ((p = findnode_fn (list, entdata->user)) != NULL) - { - /* take it out */ - delnode (p); - } - - /* get a node and fill in the regular stuff */ - p = getnode (); - p->type = ENTRIES; - p->delproc = Entries_delproc; - - /* this one gets a key of the name for hashing */ - /* FIXME This results in duplicated data --- the hash package shouldn't - assume that the key is dynamically allocated. The user's free proc - should be responsible for freeing the key. */ - p->key = xstrdup (entdata->user); - p->data = entdata; - - /* put the node into the list */ - addnode (list, p); - return (p); -} - -static char *root_template; - -static int -get_root_template(const char *repository, const char *path) -{ - if (root_template) { - if (strcmp(path, root_template) == 0) - return(0); - free(root_template); - } - if ((root_template = strdup(path)) == NULL) - return(-1); - return(0); -} - -/* - * Write out/Clear the CVS/Template file. - */ -void -WriteTemplate (dir, update_dir) - const char *dir; - const char *update_dir; -{ - char *tmp = NULL; - struct stat st1; - struct stat st2; - - if (Parse_Info(CVSROOTADM_RCSINFO, "cvs", get_root_template, 1) < 0) - return; - - if (asprintf(&tmp, "%s/%s", dir, CVSADM_TEMPLATE) < 0) - error (1, errno, "out of memory"); - - if (stat(root_template, &st1) == 0) { - if (stat(tmp, &st2) < 0 || st1.st_mtime != st2.st_mtime) { - FILE *fi; - FILE *fo; - - if ((fi = open_file(root_template, "r")) != NULL) { - if ((fo = open_file(tmp, "w")) != NULL) { - int n; - char buf[256]; - - while ((n = fread(buf, 1, sizeof(buf), fi)) > 0) - fwrite(buf, 1, n, fo); - fflush(fo); - if (ferror(fi) || ferror(fo)) { - fclose(fo); - remove(tmp); - error (1, errno, "error copying Template"); - } else { - struct timeval times[2]; - fclose(fo); - times[0].tv_sec = st1.st_mtime; - times[0].tv_usec = 0; - times[1] = times[0]; - utimes(tmp, times); - } - } - fclose(fi); - } - } - } - free(tmp); -} - -/* - * Write out/Clear the CVS/Tag file. - */ -void -WriteTag (dir, tag, date, nonbranch, update_dir, repository) - const char *dir; - const char *tag; - const char *date; - int nonbranch; - const char *update_dir; - const char *repository; -{ - FILE *fout; - char *tmp; - - if (noexec) - return; - - tmp = xmalloc ((dir ? strlen (dir) : 0) - + sizeof (CVSADM_TAG) - + 10); - if (dir == NULL) - (void) strcpy (tmp, CVSADM_TAG); - else - (void) sprintf (tmp, "%s/%s", dir, CVSADM_TAG); - - if (tag || date) - { - fout = open_file (tmp, "w+"); - if (tag) - { - if (nonbranch) - { - if (fprintf (fout, "N%s\n", tag) < 0) - error (1, errno, "write to %s failed", tmp); - } - else - { - if (fprintf (fout, "T%s\n", tag) < 0) - error (1, errno, "write to %s failed", tmp); - } - } - else - { - if (fprintf (fout, "D%s\n", date) < 0) - error (1, errno, "write to %s failed", tmp); - } - if (fclose (fout) == EOF) - error (1, errno, "cannot close %s", tmp); - } - else - if (unlink_file (tmp) < 0 && ! existence_error (errno)) - error (1, errno, "cannot remove %s", tmp); - free (tmp); -#ifdef SERVER_SUPPORT - if (server_active) - server_set_sticky (update_dir, repository, tag, date, nonbranch); -#endif -} - -/* Parse the CVS/Tag file for the current directory. - - If it contains a date, sets *DATEP to the date in a newly malloc'd - string, *TAGP to NULL, and *NONBRANCHP to an unspecified value. - - If it contains a branch tag, sets *TAGP to the tag in a newly - malloc'd string, *NONBRANCHP to 0, and *DATEP to NULL. - - If it contains a nonbranch tag, sets *TAGP to the tag in a newly - malloc'd string, *NONBRANCHP to 1, and *DATEP to NULL. - - If it does not exist, or contains something unrecognized by this - version of CVS, set *DATEP and *TAGP to NULL and *NONBRANCHP to - an unspecified value. - - If there is an error, print an error message, set *DATEP and *TAGP - to NULL, and return. */ -void -ParseTag (tagp, datep, nonbranchp) - char **tagp; - char **datep; - int *nonbranchp; -{ - FILE *fp; - - if (tagp) - *tagp = (char *) NULL; - if (datep) - *datep = (char *) NULL; - /* Always store a value here, even in the 'D' case where the value - is unspecified. Shuts up tools which check for references to - uninitialized memory. */ - if (nonbranchp != NULL) - *nonbranchp = 0; - fp = CVS_FOPEN (CVSADM_TAG, "r"); - if (fp) - { - char *line; - int line_length; - size_t line_chars_allocated; - - line = NULL; - line_chars_allocated = 0; - - if ((line_length = getline (&line, &line_chars_allocated, fp)) > 0) - { - /* Remove any trailing newline. */ - if (line[line_length - 1] == '\n') - line[--line_length] = '\0'; - switch (*line) - { - case 'T': - if (tagp != NULL) - *tagp = xstrdup (line + 1); - break; - case 'D': - if (datep != NULL) - *datep = xstrdup (line + 1); - break; - case 'N': - if (tagp != NULL) - *tagp = xstrdup (line + 1); - if (nonbranchp != NULL) - *nonbranchp = 1; - break; - default: - /* Silently ignore it; it may have been - written by a future version of CVS which extends the - syntax. */ - break; - } - } - - if (line_length < 0) - { - /* FIXME-update-dir: should include update_dir in messages. */ - if (feof (fp)) - error (0, 0, "cannot read %s: end of file", CVSADM_TAG); - else - error (0, errno, "cannot read %s", CVSADM_TAG); - } - - if (fclose (fp) < 0) - /* FIXME-update-dir: should include update_dir in message. */ - error (0, errno, "cannot close %s", CVSADM_TAG); - - free (line); - } - else if (!existence_error (errno)) - /* FIXME-update-dir: should include update_dir in message. */ - error (0, errno, "cannot open %s", CVSADM_TAG); -} - -/* - * This is called if all subdirectory information is known, but there - * aren't any subdirectories. It records that fact in the list - * private data. - */ - -void -Subdirs_Known (entries) - List *entries; -{ - struct stickydirtag *sdtp = entries->list->data; - - /* If there is no list private data, that means that the - subdirectory information is known. */ - if (sdtp != NULL && ! sdtp->subdirs) - { - FILE *fp; - - sdtp->subdirs = 1; - if (!noexec) - { - /* Create Entries.Log so that Entries_Close will do something. */ - entfilename = CVSADM_ENTLOG; - fp = CVS_FOPEN (entfilename, "a"); - if (fp == NULL) - { - int save_errno = errno; - - /* As in subdir_record, just silently skip the whole thing - if there is no CVSADM directory. */ - if (! isdir (CVSADM)) - return; - error (1, save_errno, "cannot open %s", entfilename); - } - else - { - if (fclose (fp) == EOF) - error (1, errno, "cannot close %s", entfilename); - } - } - } -} - -/* Record subdirectory information. */ - -static Entnode * -subdir_record (cmd, parent, dir) - int cmd; - const char *parent; - const char *dir; -{ - Entnode *entnode; - - /* None of the information associated with a directory is - currently meaningful. */ - entnode = Entnode_Create (ENT_SUBDIR, dir, "", "", "", - (char *) NULL, (char *) NULL, - (char *) NULL); - - if (!noexec) - { - if (parent == NULL) - entfilename = CVSADM_ENTLOG; - else - { - entfilename = xmalloc (strlen (parent) - + sizeof CVSADM_ENTLOG - + 10); - sprintf (entfilename, "%s/%s", parent, CVSADM_ENTLOG); - } - - entfile = CVS_FOPEN (entfilename, "a"); - if (entfile == NULL) - { - int save_errno = errno; - - /* It is not an error if there is no CVS administration - directory. Permitting this case simplifies some - calling code. */ - - if (parent == NULL) - { - if (! isdir (CVSADM)) - return entnode; - } - else - { - sprintf (entfilename, "%s/%s", parent, CVSADM); - if (! isdir (entfilename)) - { - free (entfilename); - entfilename = NULL; - return entnode; - } - } - - error (1, save_errno, "cannot open %s", entfilename); - } - - if (fprintf (entfile, "%c ", cmd) < 0) - error (1, errno, "cannot write %s", entfilename); - - if (fputentent (entfile, entnode) != 0) - error (1, errno, "cannot write %s", entfilename); - - if (fclose (entfile) == EOF) - error (1, errno, "error closing %s", entfilename); - - if (parent != NULL) - { - free (entfilename); - entfilename = NULL; - } - } - - return entnode; -} - -/* - * Record the addition of a new subdirectory DIR in PARENT. PARENT - * may be NULL, which means the current directory. ENTRIES is the - * current entries list; it may be NULL, which means that it need not - * be updated. - */ - -void -Subdir_Register (entries, parent, dir) - List *entries; - const char *parent; - const char *dir; -{ - Entnode *entnode; - - /* Ignore attempts to register ".". These can happen in the - server code. */ - if (dir[0] == '.' && dir[1] == '\0') - return; - - entnode = subdir_record ('A', parent, dir); - - if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0)) - (void) AddEntryNode (entries, entnode); - else - Entnode_Destroy (entnode); -} - -/* - * Record the removal of a subdirectory. The arguments are the same - * as for Subdir_Register. - */ - -void -Subdir_Deregister (entries, parent, dir) - List *entries; - const char *parent; - const char *dir; -{ - Entnode *entnode; - - entnode = subdir_record ('R', parent, dir); - Entnode_Destroy (entnode); - - if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0)) - { - Node *p; - - p = findnode_fn (entries, dir); - if (p != NULL) - delnode (p); - } -} - - - -/* OK, the following base_* code tracks the revisions of the files in - CVS/Base. We do this in a file CVS/Baserev. Separate from - CVS/Entries because it needs to go in separate data structures - anyway (the name in Entries must be unique), so this seemed - cleaner. The business of rewriting the whole file in - base_deregister and base_register is the kind of thing we used to - do for Entries and which turned out to be slow, which is why there - is now the Entries.Log machinery. So maybe from that point of - view it is a mistake to do this separately from Entries, I dunno. - - We also need something analogous for: - - 1. CVS/Template (so we can update the Template file automagically - without the user needing to check out a new working directory). - Updating would probably print a message (that part might be - optional, although probably it should be visible because not all - cvs commands would make the update happen and so it is a - user-visible behavior). Constructing version number for template - is a bit hairy (base it on the timestamp on the server? Or see if - the template is in checkoutlist and if yes use its versioning and - if no don't version it?).... - - 2. cvsignore (need to keep a copy in the working directory to do - "cvs release" on the client side; see comment at src/release.c - (release). Would also allow us to stop needing Questionable. */ - -enum base_walk { - /* Set the revision for FILE to *REV. */ - BASE_REGISTER, - /* Get the revision for FILE and put it in a newly malloc'd string - in *REV, or put NULL if not mentioned. */ - BASE_GET, - /* Remove FILE. */ - BASE_DEREGISTER -}; - -static void base_walk PROTO ((enum base_walk, struct file_info *, char **)); - -/* Read through the lines in CVS/Baserev, taking the actions as documented - for CODE. */ - -static void -base_walk (code, finfo, rev) - enum base_walk code; - struct file_info *finfo; - char **rev; -{ - FILE *fp; - char *line; - size_t line_allocated; - FILE *newf; - char *baserev_fullname; - char *baserevtmp_fullname; - - line = NULL; - line_allocated = 0; - newf = NULL; - - /* First compute the fullnames for the error messages. This - computation probably should be broken out into a separate function, - as recurse.c does it too and places like Entries_Open should be - doing it. */ - baserev_fullname = xmalloc (sizeof (CVSADM_BASEREV) - + strlen (finfo->update_dir) - + 2); - baserev_fullname[0] = '\0'; - baserevtmp_fullname = xmalloc (sizeof (CVSADM_BASEREVTMP) - + strlen (finfo->update_dir) - + 2); - baserevtmp_fullname[0] = '\0'; - if (finfo->update_dir[0] != '\0') - { - strcat (baserev_fullname, finfo->update_dir); - strcat (baserev_fullname, "/"); - strcat (baserevtmp_fullname, finfo->update_dir); - strcat (baserevtmp_fullname, "/"); - } - strcat (baserev_fullname, CVSADM_BASEREV); - strcat (baserevtmp_fullname, CVSADM_BASEREVTMP); - - fp = CVS_FOPEN (CVSADM_BASEREV, "r"); - if (fp == NULL) - { - if (!existence_error (errno)) - { - error (0, errno, "cannot open %s for reading", baserev_fullname); - goto out; - } - } - - switch (code) - { - case BASE_REGISTER: - case BASE_DEREGISTER: - newf = CVS_FOPEN (CVSADM_BASEREVTMP, "w"); - if (newf == NULL) - { - error (0, errno, "cannot open %s for writing", - baserevtmp_fullname); - goto out; - } - break; - case BASE_GET: - *rev = NULL; - break; - } - - if (fp != NULL) - { - while (getline (&line, &line_allocated, fp) >= 0) - { - char *linefile; - char *p; - char *linerev; - - if (line[0] != 'B') - /* Ignore, for future expansion. */ - continue; - - linefile = line + 1; - p = strchr (linefile, '/'); - if (p == NULL) - /* Syntax error, ignore. */ - continue; - linerev = p + 1; - p = strchr (linerev, '/'); - if (p == NULL) - continue; - - linerev[-1] = '\0'; - if (fncmp (linefile, finfo->file) == 0) - { - switch (code) - { - case BASE_REGISTER: - case BASE_DEREGISTER: - /* Don't copy over the old entry, we don't want it. */ - break; - case BASE_GET: - *p = '\0'; - *rev = xstrdup (linerev); - *p = '/'; - goto got_it; - } - } - else - { - linerev[-1] = '/'; - switch (code) - { - case BASE_REGISTER: - case BASE_DEREGISTER: - if (fprintf (newf, "%s\n", line) < 0) - error (0, errno, "error writing %s", - baserevtmp_fullname); - break; - case BASE_GET: - break; - } - } - } - if (ferror (fp)) - error (0, errno, "cannot read %s", baserev_fullname); - } - got_it: - - if (code == BASE_REGISTER) - { - if (fprintf (newf, "B%s/%s/\n", finfo->file, *rev) < 0) - error (0, errno, "error writing %s", - baserevtmp_fullname); - } - - out: - - if (line != NULL) - free (line); - - if (fp != NULL) - { - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", baserev_fullname); - } - if (newf != NULL) - { - if (fclose (newf) < 0) - error (0, errno, "cannot close %s", baserevtmp_fullname); - rename_file (CVSADM_BASEREVTMP, CVSADM_BASEREV); - } - - free (baserev_fullname); - free (baserevtmp_fullname); -} - -/* Return, in a newly malloc'd string, the revision for FILE in CVS/Baserev, - or NULL if not listed. */ - -char * -base_get (finfo) - struct file_info *finfo; -{ - char *rev; - base_walk (BASE_GET, finfo, &rev); - return rev; -} - -/* Set the revision for FILE to REV. */ - -void -base_register (finfo, rev) - struct file_info *finfo; - char *rev; -{ - base_walk (BASE_REGISTER, finfo, &rev); -} - -/* Remove FILE. */ - -void -base_deregister (finfo) - struct file_info *finfo; -{ - base_walk (BASE_DEREGISTER, finfo, NULL); -} diff --git a/contrib/cvs/src/error.c b/contrib/cvs/src/error.c deleted file mode 100644 index 129ba9b..0000000 --- a/contrib/cvs/src/error.c +++ /dev/null @@ -1,255 +0,0 @@ -/* error.c -- error handler for noninteractive utilities - Copyright (C) 1990-1992 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -/* David MacKenzie */ -/* Brian Berliner added support for CVS */ - -#include "cvs.h" - -#include <stdio.h> - -/* If non-zero, error will use the CVS protocol to stdout to report error - messages. This will only be set in the CVS server parent process; - most other code is run via do_cvs_command, which forks off a child - process and packages up its stderr in the protocol. */ -int error_use_protocol; - -#ifdef HAVE_VPRINTF - -#ifdef __STDC__ -#include <stdarg.h> -#define VA_START(args, lastarg) va_start(args, lastarg) -#else /* ! __STDC__ */ -#include <varargs.h> -#define VA_START(args, lastarg) va_start(args) -#endif /* __STDC__ */ - -#else /* ! HAVE_VPRINTF */ - -#ifdef HAVE_DOPRNT -#define va_alist args -#define va_dcl int args; -#else /* ! HAVE_DOPRNT */ -#define va_alist a1, a2, a3, a4, a5, a6, a7, a8 -#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; -#endif /* HAVE_DOPRNT */ - -#endif /* HAVE_VPRINTF */ - -#if STDC_HEADERS -#include <stdlib.h> -#include <string.h> -#else /* ! STDC_HEADERS */ -#ifdef __STDC__ -void exit(int status); -#else /* ! __STDC__ */ -void exit (); -#endif /* __STDC__ */ -#endif /* STDC_HEADERS */ - -#ifndef strerror -extern char *strerror (); -#endif - -void -error_exit PROTO ((void)) -{ - rcs_cleanup (); - Lock_Cleanup (); -#ifdef SERVER_SUPPORT - if (server_active) - server_cleanup (0); -#endif -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - exit (EXIT_FAILURE); -} - -/* Print the program name and error message MESSAGE, which is a printf-style - format string with optional args. This is a very limited printf subset: - %s, %d, %c, %x and %% only (without anything between the % and the s, - d, &c). Callers who want something fancier can use sprintf. - - If ERRNUM is nonzero, print its corresponding system error message. - Exit with status EXIT_FAILURE if STATUS is nonzero. If MESSAGE is "", - no need to print a message. - - I think this is largely cleaned up to the point where it does the right - thing for the server, whether the normal server_active (child process) - case or the error_use_protocol (parent process) case. The one exception - is that STATUS nonzero for error_use_protocol probably doesn't work yet; - in that case still need to use the pending_error machinery in server.c. - - error() does not molest errno; some code (e.g. Entries_Open) depends - on being able to say something like: - error (0, 0, "foo"); - error (0, errno, "bar"); - - */ - -/* VARARGS */ -void -#if defined (__STDC__) -error (int status, int errnum, const char *message, ...) -#else -error (status, errnum, message, va_alist) - int status; - int errnum; - const char *message; - va_dcl -#endif -{ - int save_errno = errno; - - if (message[0] != '\0') - { - va_list args; - const char *p; - char *q; - char *str; - int num; - long lnum; - unsigned int unum; - unsigned long ulnum; - int ch; - char buf[100]; - - cvs_outerr (program_name, 0); - if (cvs_cmd_name && *cvs_cmd_name) - { - cvs_outerr (" ", 1); - if (status != 0) - cvs_outerr ("[", 1); - cvs_outerr (cvs_cmd_name, 0); - if (status != 0) - cvs_outerr (" aborted]", 0); - } - cvs_outerr (": ", 2); - - VA_START (args, message); - p = message; - while ((q = strchr (p, '%')) != NULL) - { - static const char msg[] = - "\ninternal error: bad % in error()\n"; - if (q - p > 0) - cvs_outerr (p, q - p); - - switch (q[1]) - { - case 's': - str = va_arg (args, char *); - cvs_outerr (str, strlen (str)); - break; - case 'd': - num = va_arg (args, int); - sprintf (buf, "%d", num); - cvs_outerr (buf, strlen (buf)); - break; - case 'l': - if (q[2] == 'd') - { - lnum = va_arg (args, long); - sprintf (buf, "%ld", lnum); - } - else if (q[2] == 'u') - { - ulnum = va_arg (args, unsigned long); - sprintf (buf, "%lu", ulnum); - } - else goto bad; - cvs_outerr (buf, strlen (buf)); - q++; - break; - case 'x': - unum = va_arg (args, unsigned int); - sprintf (buf, "%x", unum); - cvs_outerr (buf, strlen (buf)); - break; - case 'c': - ch = va_arg (args, int); - buf[0] = ch; - cvs_outerr (buf, 1); - break; - case '%': - cvs_outerr ("%", 1); - break; - default: - bad: - cvs_outerr (msg, sizeof (msg) - 1); - /* Don't just keep going, because q + 1 might point to the - terminating '\0'. */ - goto out; - } - p = q + 2; - } - cvs_outerr (p, strlen (p)); - out: - va_end (args); - - if (errnum != 0) - { - cvs_outerr (": ", 2); - cvs_outerr (strerror (errnum), 0); - } - cvs_outerr ("\n", 1); - } - - if (status) - error_exit (); - errno = save_errno; -} - -/* Print the program name and error message MESSAGE, which is a printf-style - format string with optional args to the file specified by FP. - If ERRNUM is nonzero, print its corresponding system error message. - Exit with status EXIT_FAILURE if STATUS is nonzero. */ -/* VARARGS */ -void -#if defined (HAVE_VPRINTF) && defined (__STDC__) -fperrmsg (FILE *fp, int status, int errnum, char *message, ...) -#else -fperrmsg (fp, status, errnum, message, va_alist) - FILE *fp; - int status; - int errnum; - char *message; - va_dcl -#endif -{ -#ifdef HAVE_VPRINTF - va_list args; -#endif - - fprintf (fp, "%s: ", program_name); -#ifdef HAVE_VPRINTF - VA_START (args, message); - vfprintf (fp, message, args); - va_end (args); -#else -#ifdef HAVE_DOPRNT - _doprnt (message, &args, fp); -#else - fprintf (fp, message, a1, a2, a3, a4, a5, a6, a7, a8); -#endif -#endif - if (errnum) - fprintf (fp, ": %s", strerror (errnum)); - putc ('\n', fp); - fflush (fp); - if (status) - error_exit (); -} diff --git a/contrib/cvs/src/error.h b/contrib/cvs/src/error.h deleted file mode 100644 index 1c8471d..0000000 --- a/contrib/cvs/src/error.h +++ /dev/null @@ -1,62 +0,0 @@ -/* error.h -- declaration for error-reporting function - Copyright (C) 1995 Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -#ifndef ERROR_H -#define ERROR_H - -/* Add prototype support. Normally this is done in cvs.h, but that - doesn't get included from lib/savecwd.c. */ -#ifndef PROTO -#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) -#define PROTO(ARGS) ARGS -#else -#define PROTO(ARGS) () -#endif -#endif - -#ifndef __attribute__ -/* This feature is available in gcc versions 2.5 and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ -# define __attribute__(Spec) /* empty */ -# endif -/* The __-protected variants of `format' and `printf' attributes - are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) -# define __format__ format -# define __printf__ printf -# define __noreturn__ noreturn -# endif -#endif - -#ifdef __STDC__ -void error (int, int, const char *, ...) \ - __attribute__ ((__format__ (__printf__, 3, 4))); -#else -void error (); -#endif - -/* Exit due to an error. Similar to error (1, 0, "message"), but call - it in the case where the message has already been printed. */ -#ifdef __STDC__ -void error_exit (void) __attribute__ ((__noreturn__)); -#else -void error_exit (); -#endif - -/* If non-zero, error will use the CVS protocol to report error - messages. This will only be set in the CVS server parent process; - most other code is run via do_cvs_command, which forks off a child - process and packages up its stderr in the protocol. */ -extern int error_use_protocol; - -#endif /* ERROR_H */ diff --git a/contrib/cvs/src/expand_path.c b/contrib/cvs/src/expand_path.c deleted file mode 100644 index 1c960f3..0000000 --- a/contrib/cvs/src/expand_path.c +++ /dev/null @@ -1,318 +0,0 @@ -/* expand_path.c -- expand environmental variables in passed in string - * - * Copyright (C) 1995-2005 The Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * The main routine is expand_path(), it is the routine that handles - * the '~' character in four forms: - * ~name - * ~name/ - * ~/ - * ~ - * and handles environment variables contained within the pathname - * which are defined by: - * ${var_name} (var_name is the name of the environ variable) - * $var_name (var_name ends w/ non-alphanumeric char other than '_') - */ - -#include "cvs.h" -#include <sys/types.h> - -static char *expand_variable PROTO((const char *env, const char *file, - int line)); - - - -/* User variables. */ - -List *variable_list = NULL; - -static void variable_delproc PROTO ((Node *)); - -static void -variable_delproc (node) - Node *node; -{ - free (node->data); -} - -/* Currently used by -s option; we might want a way to set user - variables in a file in the $CVSROOT/CVSROOT directory too. */ - -void -variable_set (nameval) - char *nameval; -{ - char *p; - char *name; - Node *node; - - p = nameval; - while (isalnum ((unsigned char) *p) || *p == '_') - ++p; - if (*p != '=') - error (1, 0, "illegal character in user variable name in %s", nameval); - if (p == nameval) - error (1, 0, "empty user variable name in %s", nameval); - name = xmalloc (p - nameval + 1); - strncpy (name, nameval, p - nameval); - name[p - nameval] = '\0'; - /* Make p point to the value. */ - ++p; - if (strchr (p, '\012') != NULL) - error (1, 0, "linefeed in user variable value in %s", nameval); - - if (variable_list == NULL) - variable_list = getlist (); - - node = findnode (variable_list, name); - if (node == NULL) - { - node = getnode (); - node->type = VARIABLE; - node->delproc = variable_delproc; - node->key = name; - node->data = xstrdup (p); - (void) addnode (variable_list, node); - } - else - { - /* Replace the old value. For example, this means that -s - options on the command line override ones from .cvsrc. */ - free (node->data); - node->data = xstrdup (p); - free (name); - } -} - - - -/* This routine will expand the pathname to account for ~ and $ - characters as described above. Returns a pointer to a newly - malloc'd string. If an error occurs, an error message is printed - via error() and NULL is returned. FILE and LINE are the filename - and linenumber to include in the error message. FILE must point - to something; LINE can be zero to indicate the line number is not - known. */ -char * -expand_path (name, file, line) - const char *name; - const char *file; - int line; -{ - size_t s, d, p; - char *e; - - char *mybuf = NULL; - size_t mybuf_size = 0; - char *buf = NULL; - size_t buf_size = 0; - - char *result; - - /* Sorry this routine is so ugly; it is a head-on collision - between the `traditional' unix *d++ style and the need to - dynamically allocate. It would be much cleaner (and probably - faster, not that this is a bottleneck for CVS) with more use of - strcpy & friends, but I haven't taken the effort to rewrite it - thusly. */ - - /* First copy from NAME to MYBUF, expanding $<foo> as we go. */ - s = d = 0; - while (name[s] != '\0') - { - if (name[s] == '$') - { - p = d; - if (name[++s] == '{') - { - while (name[++s] != '}' && name[s] != '\0') - { - expand_string (&mybuf, &mybuf_size, p + 1); - mybuf[p++] = name[s]; - } - if (name[s] != '\0') ++s; - } - else - { - while (isalnum ((unsigned char) name[s]) || name[s] == '_') - { - expand_string (&mybuf, &mybuf_size, p + 1); - mybuf[p++] = name[s++]; - } - } - expand_string (&mybuf, &mybuf_size, p + 1); - mybuf[p] = '\0'; - e = expand_variable (mybuf + d, file, line); - - if (e) - { - p = strlen(e); - expand_string (&mybuf, &mybuf_size, d + p); - memcpy(mybuf + d, e, p); - d += p; - } - else - /* expand_variable has already printed an error message. */ - goto error_exit; - } - else - { - expand_string (&mybuf, &mybuf_size, d + 1); - mybuf[d++] = name[s++]; - } - } - expand_string (&mybuf, &mybuf_size, d + 1); - mybuf[d++] = '\0'; - - /* Then copy from MYBUF to BUF, expanding ~. */ - s = d = 0; - /* If you don't want ~username ~/ to be expanded simply remove - * This entire if statement including the else portion - */ - if (mybuf[s] == '~') - { - p = d; - while (mybuf[++s] != '/' && mybuf[s] != '\0') - { - expand_string (&buf, &buf_size, p + 1); - buf[p++] = name[s]; - } - expand_string (&buf, &buf_size, p + 1); - buf[p] = '\0'; - - if (p == d) - e = get_homedir (); - else - { -#ifdef GETPWNAM_MISSING - if (line != 0) - error (0, 0, - "%s:%d:tilde expansion not supported on this system", - file, line); - else - error (0, 0, "%s:tilde expansion not supported on this system", - file); - goto error_exit; -#else - struct passwd *ps; - ps = getpwnam (buf + d); - if (ps == NULL) - { - if (line != 0) - error (0, 0, "%s:%d: no such user %s", - file, line, buf + d); - else - error (0, 0, "%s: no such user %s", file, buf + d); - goto error_exit; - } - e = ps->pw_dir; -#endif - } - if (e == NULL) - error (1, 0, "cannot find home directory"); - - p = strlen(e); - expand_string (&buf, &buf_size, d + p); - memcpy(buf + d, e, p); - d += p; - } - /* Kill up to here */ - p = strlen(mybuf + s) + 1; - expand_string (&buf, &buf_size, d + p); - memcpy(buf + d, mybuf + s, p); - - /* OK, buf contains the value we want to return. Clean up and return - it. */ - free (mybuf); - /* Save a little memory with xstrdup; buf will tend to allocate - more than it needs to. */ - result = xstrdup (buf); - free (buf); - return result; - - error_exit: - if (mybuf != NULL) - free (mybuf); - if (buf != NULL) - free (buf); - return NULL; -} - -static char * -expand_variable (name, file, line) - const char *name; - const char *file; - int line; -{ - if (strcmp (name, CVSROOT_ENV) == 0) - return current_parsed_root->directory; - else if (strcmp (name, "RCSBIN") == 0) - { - error (0, 0, "RCSBIN internal variable is no longer supported"); - return NULL; - } - else if (strcmp (name, EDITOR1_ENV) == 0) - return Editor; - else if (strcmp (name, EDITOR2_ENV) == 0) - return Editor; - else if (strcmp (name, EDITOR3_ENV) == 0) - return Editor; - else if (strcmp (name, "USER") == 0) - return getcaller (); - else if (isalpha ((unsigned char) name[0])) - { - /* These names are reserved for future versions of CVS, - so that is why it is an error. */ - if (line != 0) - error (0, 0, "%s:%d: no such internal variable $%s", - file, line, name); - else - error (0, 0, "%s: no such internal variable $%s", - file, name); - return NULL; - } - else if (name[0] == '=') - { - Node *node; - /* Crazy syntax for a user variable. But we want - *something* that lets the user name a user variable - anything he wants, without interference from - (existing or future) internal variables. */ - node = findnode (variable_list, name + 1); - if (node == NULL) - { - if (line != 0) - error (0, 0, "%s:%d: no such user variable ${%s}", - file, line, name); - else - error (0, 0, "%s: no such user variable ${%s}", - file, name); - return NULL; - } - return node->data; - } - else - { - /* It is an unrecognized character. We return an error to - reserve these for future versions of CVS; it is plausible - that various crazy syntaxes might be invented for inserting - information about revisions, branches, etc. */ - if (line != 0) - error (0, 0, "%s:%d: unrecognized variable syntax %s", - file, line, name); - else - error (0, 0, "%s: unrecognized variable syntax %s", - file, name); - return NULL; - } -} diff --git a/contrib/cvs/src/fileattr.c b/contrib/cvs/src/fileattr.c deleted file mode 100644 index ca6bd0e..0000000 --- a/contrib/cvs/src/fileattr.c +++ /dev/null @@ -1,656 +0,0 @@ -/* Implementation for file attribute munging features. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -#include "cvs.h" -#include "getline.h" -#include "fileattr.h" -#include <assert.h> - -static void fileattr_read PROTO ((void)); -static int writeattr_proc PROTO ((Node *, void *)); - -/* Where to look for CVSREP_FILEATTR. */ -static char *fileattr_stored_repos; - -/* The in-memory attributes. */ -static List *attrlist; -static char *fileattr_default_attrs; -/* We have already tried to read attributes and failed in this directory - (for example, there is no CVSREP_FILEATTR file). */ -static int attr_read_attempted; - -/* Have the in-memory attributes been modified since we read them? */ -static int attrs_modified; - -/* More in-memory attributes: linked list of unrecognized - fileattr lines. We pass these on unchanged. */ -struct unrecog { - char *line; - struct unrecog *next; -}; -static struct unrecog *unrecog_head; - -/* Note that if noone calls fileattr_get, this is very cheap. No stat(), - no open(), no nothing. */ -void -fileattr_startdir (repos) - const char *repos; -{ - assert (fileattr_stored_repos == NULL); - fileattr_stored_repos = xstrdup (repos); - assert (attrlist == NULL); - attr_read_attempted = 0; - assert (unrecog_head == NULL); -} - -static void -fileattr_delproc (node) - Node *node; -{ - assert (node->data != NULL); - free (node->data); - node->data = NULL; -} - -/* Read all the attributes for the current directory into memory. */ -static void -fileattr_read () -{ - char *fname; - FILE *fp; - char *line = NULL; - size_t line_len = 0; - - /* If there are no attributes, don't waste time repeatedly looking - for the CVSREP_FILEATTR file. */ - if (attr_read_attempted) - return; - - /* If NULL was passed to fileattr_startdir, then it isn't kosher to look - at attributes. */ - assert (fileattr_stored_repos != NULL); - - fname = xmalloc (strlen (fileattr_stored_repos) - + 1 - + sizeof (CVSREP_FILEATTR) - + 1); - - strcpy (fname, fileattr_stored_repos); - strcat (fname, "/"); - strcat (fname, CVSREP_FILEATTR); - - attr_read_attempted = 1; - fp = CVS_FOPEN (fname, FOPEN_BINARY_READ); - if (fp == NULL) - { - if (!existence_error (errno)) - error (0, errno, "cannot read %s", fname); - free (fname); - return; - } - attrlist = getlist (); - while (1) { - int nread; - nread = getline (&line, &line_len, fp); - if (nread < 0) - break; - /* Remove trailing newline. */ - line[nread - 1] = '\0'; - if (line[0] == 'F') - { - char *p; - Node *newnode; - - p = strchr (line, '\t'); - if (p == NULL) - error (1, 0, - "file attribute database corruption: tab missing in %s", - fname); - *p++ = '\0'; - newnode = getnode (); - newnode->type = FILEATTR; - newnode->delproc = fileattr_delproc; - newnode->key = xstrdup (line + 1); - newnode->data = xstrdup (p); - if (addnode (attrlist, newnode) != 0) - /* If the same filename appears twice in the file, discard - any line other than the first for that filename. This - is the way that CVS has behaved since file attributes - were first introduced. */ - freenode (newnode); - } - else if (line[0] == 'D') - { - char *p; - /* Currently nothing to skip here, but for future expansion, - ignore anything located here. */ - p = strchr (line, '\t'); - if (p == NULL) - error (1, 0, - "file attribute database corruption: tab missing in %s", - fname); - ++p; - if (fileattr_default_attrs) free (fileattr_default_attrs); - fileattr_default_attrs = xstrdup (p); - } - else - { - /* Unrecognized type, we want to just preserve the line without - changing it, for future expansion. */ - struct unrecog *new; - - new = (struct unrecog *) xmalloc (sizeof (struct unrecog)); - new->line = xstrdup (line); - new->next = unrecog_head; - unrecog_head = new; - } - } - if (ferror (fp)) - error (0, errno, "cannot read %s", fname); - if (line != NULL) - free (line); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", fname); - attrs_modified = 0; - free (fname); -} - -char * -fileattr_get (filename, attrname) - const char *filename; - const char *attrname; -{ - Node *node; - size_t attrname_len = strlen (attrname); - char *p; - - if (attrlist == NULL) - fileattr_read (); - if (attrlist == NULL) - /* Either nothing has any attributes, or fileattr_read already printed - an error message. */ - return NULL; - - if (filename == NULL) - p = fileattr_default_attrs; - else - { - node = findnode (attrlist, filename); - if (node == NULL) - /* A file not mentioned has no attributes. */ - return NULL; - p = node->data; - } - while (p) - { - if (strncmp (attrname, p, attrname_len) == 0 - && p[attrname_len] == '=') - { - /* Found it. */ - return p + attrname_len + 1; - } - p = strchr (p, ';'); - if (p == NULL) - break; - ++p; - } - /* The file doesn't have this attribute. */ - return NULL; -} - -char * -fileattr_get0 (filename, attrname) - const char *filename; - const char *attrname; -{ - char *cp; - char *cpend; - char *retval; - - cp = fileattr_get (filename, attrname); - if (cp == NULL) - return NULL; - cpend = strchr (cp, ';'); - if (cpend == NULL) - cpend = cp + strlen (cp); - retval = xmalloc (cpend - cp + 1); - strncpy (retval, cp, cpend - cp); - retval[cpend - cp] = '\0'; - return retval; -} - -char * -fileattr_modify (list, attrname, attrval, namevalsep, entsep) - char *list; - const char *attrname; - const char *attrval; - int namevalsep; - int entsep; -{ - char *retval; - char *rp; - size_t attrname_len = strlen (attrname); - - /* Portion of list before the attribute to be replaced. */ - char *pre; - char *preend; - /* Portion of list after the attribute to be replaced. */ - char *post; - - char *p; - char *p2; - - p = list; - pre = list; - preend = NULL; - /* post is NULL unless set otherwise. */ - post = NULL; - p2 = NULL; - if (list != NULL) - { - while (1) { - p2 = strchr (p, entsep); - if (p2 == NULL) - { - p2 = p + strlen (p); - if (preend == NULL) - preend = p2; - } - else - ++p2; - if (strncmp (attrname, p, attrname_len) == 0 - && p[attrname_len] == namevalsep) - { - /* Found it. */ - preend = p; - if (preend > list) - /* Don't include the preceding entsep. */ - --preend; - - post = p2; - } - if (p2[0] == '\0') - break; - p = p2; - } - } - if (post == NULL) - post = p2; - - if (preend == pre && attrval == NULL && post == p2) - return NULL; - - retval = xmalloc ((preend - pre) - + 1 - + (attrval == NULL ? 0 : (attrname_len + 1 - + strlen (attrval))) - + 1 - + (p2 - post) - + 1); - if (preend != pre) - { - strncpy (retval, pre, preend - pre); - rp = retval + (preend - pre); - if (attrval != NULL) - *rp++ = entsep; - *rp = '\0'; - } - else - retval[0] = '\0'; - if (attrval != NULL) - { - strcat (retval, attrname); - rp = retval + strlen (retval); - *rp++ = namevalsep; - strcpy (rp, attrval); - } - if (post != p2) - { - rp = retval + strlen (retval); - if (preend != pre || attrval != NULL) - *rp++ = entsep; - strncpy (rp, post, p2 - post); - rp += p2 - post; - *rp = '\0'; - } - return retval; -} - -void -fileattr_set (filename, attrname, attrval) - const char *filename; - const char *attrname; - const char *attrval; -{ - Node *node; - char *p; - - if (filename == NULL) - { - p = fileattr_modify (fileattr_default_attrs, attrname, attrval, - '=', ';'); - if (fileattr_default_attrs != NULL) - free (fileattr_default_attrs); - fileattr_default_attrs = p; - attrs_modified = 1; - return; - } - if (attrlist == NULL) - fileattr_read (); - if (attrlist == NULL) - { - /* Not sure this is a graceful way to handle things - in the case where fileattr_read was unable to read the file. */ - /* No attributes existed previously. */ - attrlist = getlist (); - } - - node = findnode (attrlist, filename); - if (node == NULL) - { - if (attrval == NULL) - /* Attempt to remove an attribute which wasn't there. */ - return; - - /* First attribute for this file. */ - node = getnode (); - node->type = FILEATTR; - node->delproc = fileattr_delproc; - node->key = xstrdup (filename); - node->data = xmalloc (strlen (attrname) + 1 + strlen (attrval) + 1); - strcpy (node->data, attrname); - strcat (node->data, "="); - strcat (node->data, attrval); - addnode (attrlist, node); - } - - p = fileattr_modify (node->data, attrname, attrval, '=', ';'); - if (p == NULL) - delnode (node); - else - { - free (node->data); - node->data = p; - } - - attrs_modified = 1; -} - -char * -fileattr_getall (filename) - const char *filename; -{ - Node *node; - char *p; - - if (attrlist == NULL) - fileattr_read (); - if (attrlist == NULL) - /* Either nothing has any attributes, or fileattr_read already printed - an error message. */ - return NULL; - - if (filename == NULL) - p = fileattr_default_attrs; - else - { - node = findnode (attrlist, filename); - if (node == NULL) - /* A file not mentioned has no attributes. */ - return NULL; - p = node->data; - } - return xstrdup (p); -} - -void -fileattr_setall (filename, attrs) - const char *filename; - const char *attrs; -{ - Node *node; - - if (filename == NULL) - { - if (fileattr_default_attrs != NULL) - free (fileattr_default_attrs); - fileattr_default_attrs = xstrdup (attrs); - attrs_modified = 1; - return; - } - if (attrlist == NULL) - fileattr_read (); - if (attrlist == NULL) - { - /* Not sure this is a graceful way to handle things - in the case where fileattr_read was unable to read the file. */ - /* No attributes existed previously. */ - attrlist = getlist (); - } - - node = findnode (attrlist, filename); - if (node == NULL) - { - /* The file had no attributes. Add them if we have any to add. */ - if (attrs != NULL) - { - node = getnode (); - node->type = FILEATTR; - node->delproc = fileattr_delproc; - node->key = xstrdup (filename); - node->data = xstrdup (attrs); - addnode (attrlist, node); - } - } - else - { - if (attrs == NULL) - delnode (node); - else - { - free (node->data); - node->data = xstrdup (attrs); - } - } - - attrs_modified = 1; -} - -void -fileattr_newfile (filename) - const char *filename; -{ - Node *node; - - if (attrlist == NULL) - fileattr_read (); - - if (fileattr_default_attrs == NULL) - return; - - if (attrlist == NULL) - { - /* Not sure this is a graceful way to handle things - in the case where fileattr_read was unable to read the file. */ - /* No attributes existed previously. */ - attrlist = getlist (); - } - - node = getnode (); - node->type = FILEATTR; - node->delproc = fileattr_delproc; - node->key = xstrdup (filename); - node->data = xstrdup (fileattr_default_attrs); - addnode (attrlist, node); - attrs_modified = 1; -} - -static int -writeattr_proc (node, data) - Node *node; - void *data; -{ - FILE *fp = (FILE *)data; - fputs ("F", fp); - fputs (node->key, fp); - fputs ("\t", fp); - fputs (node->data, fp); - fputs ("\012", fp); - return 0; -} - -void -fileattr_write () -{ - FILE *fp; - char *fname; - mode_t omask; - struct unrecog *p; - - if (!attrs_modified) - return; - - if (noexec) - return; - - /* If NULL was passed to fileattr_startdir, then it isn't kosher to set - attributes. */ - assert (fileattr_stored_repos != NULL); - - fname = xmalloc (strlen (fileattr_stored_repos) - + 1 - + sizeof (CVSREP_FILEATTR) - + 1); - - strcpy (fname, fileattr_stored_repos); - strcat (fname, "/"); - strcat (fname, CVSREP_FILEATTR); - - if (list_isempty (attrlist) - && fileattr_default_attrs == NULL - && unrecog_head == NULL) - { - /* There are no attributes. */ - if (unlink_file (fname) < 0) - { - if (!existence_error (errno)) - { - error (0, errno, "cannot remove %s", fname); - } - } - - /* Now remove CVSREP directory, if empty. The main reason we bother - is that CVS 1.6 and earlier will choke if a CVSREP directory - exists, so provide the user a graceful way to remove it. */ - strcpy (fname, fileattr_stored_repos); - strcat (fname, "/"); - strcat (fname, CVSREP); - if (CVS_RMDIR (fname) < 0) - { - if (errno != ENOTEMPTY - - /* Don't know why we would be here if there is no CVSREP - directory, but it seemed to be happening anyway, so - check for it. */ - && !existence_error (errno)) - error (0, errno, "cannot remove %s", fname); - } - - free (fname); - return; - } - - omask = umask (cvsumask); - fp = CVS_FOPEN (fname, FOPEN_BINARY_WRITE); - if (fp == NULL) - { - if (existence_error (errno)) - { - /* Maybe the CVSREP directory doesn't exist. Try creating it. */ - char *repname; - - repname = xmalloc (strlen (fileattr_stored_repos) - + 1 - + sizeof (CVSREP) - + 1); - strcpy (repname, fileattr_stored_repos); - strcat (repname, "/"); - strcat (repname, CVSREP); - - if (CVS_MKDIR (repname, 0777) < 0 && errno != EEXIST) - { - error (0, errno, "cannot make directory %s", repname); - (void) umask (omask); - free (fname); - free (repname); - return; - } - free (repname); - - fp = CVS_FOPEN (fname, FOPEN_BINARY_WRITE); - } - if (fp == NULL) - { - error (0, errno, "cannot write %s", fname); - (void) umask (omask); - free (fname); - return; - } - } - (void) umask (omask); - - /* First write the "F" attributes. */ - walklist (attrlist, writeattr_proc, fp); - - /* Then the "D" attribute. */ - if (fileattr_default_attrs != NULL) - { - fputs ("D\t", fp); - fputs (fileattr_default_attrs, fp); - fputs ("\012", fp); - } - - /* Then any other attributes. */ - for (p = unrecog_head; p != NULL; p = p->next) - { - fputs (p->line, fp); - fputs ("\012", fp); - } - - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", fname); - attrs_modified = 0; - free (fname); -} - -void -fileattr_free () -{ - /* Note that attrs_modified will ordinarily be zero, but there are - a few cases in which fileattr_write will fail to zero it (if - noexec is set, or error conditions). This probably is the way - it should be. */ - dellist (&attrlist); - if (fileattr_stored_repos != NULL) - free (fileattr_stored_repos); - fileattr_stored_repos = NULL; - 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/fileattr.h b/contrib/cvs/src/fileattr.h deleted file mode 100644 index 507807c..0000000 --- a/contrib/cvs/src/fileattr.h +++ /dev/null @@ -1,136 +0,0 @@ -/* Declarations for file attribute munging features. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -#ifndef FILEATTR_H - -/* File containing per-file attributes. The format of this file is in - cvs.texinfo but here is a quick summary. The file contains a - series of entries: - - ENT-TYPE FILENAME <tab> ATTRNAME = ATTRVAL - {; ATTRNAME = ATTRVAL} <linefeed> - - ENT-TYPE is 'F' for a file. - - ENT-TYPE is 'D', and FILENAME empty, for default attributes. - - Other ENT-TYPE are reserved for future expansion. - - Note that the order of the line is not significant; CVS is free to - rearrange them at its convenience. - - FIXME: this implementation doesn't handle '\0' in any of the - fields. We are encouraged to fix this (by cvs.texinfo). - - By convention, ATTRNAME starting with '_' is for an attribute given - special meaning by CVS; other ATTRNAMEs are for user-defined attributes - (or will be, once we add commands to manipulate user-defined attributes). - - Builtin attributes: - - _watched: Present means the file is watched and should be checked out - read-only. - - _watchers: Users with watches for this file. Value is - WATCHER > TYPE { , WATCHER > TYPE } - where WATCHER is a username, and TYPE is edit,unedit,commit separated by - + (or nothing if none; there is no "none" or "all" keyword). - - _editors: Users editing this file. Value is - EDITOR > VAL { , EDITOR > VAL } - where EDITOR is a username, and VAL is TIME+HOSTNAME+PATHNAME, where - TIME is when the "cvs edit" command happened, - and HOSTNAME and PATHNAME are for the working directory. */ - -#define CVSREP_FILEATTR "CVS/fileattr" - -/* Prepare for a new directory with repository REPOS. If REPOS is NULL, - then prepare for a "non-directory"; the caller can call fileattr_write - and fileattr_free, but must not call fileattr_get or fileattr_set. */ -extern void fileattr_startdir PROTO ((const char *repos)); - -/* Get the attribute ATTRNAME for file FILENAME. The return value - points into memory managed by the fileattr_* routines, should not - be altered by the caller, and is only good until the next call to - fileattr_clear or fileattr_set. It points to the value, terminated - by '\0' or ';'. Return NULL if said file lacks said attribute. - If FILENAME is NULL, return default attributes (attributes for - files created in the future). */ -extern char *fileattr_get PROTO ((const char *filename, const char *attrname)); - -/* Like fileattr_get, but return a pointer to a newly malloc'd string - terminated by '\0' (or NULL if said file lacks said attribute). */ -extern char *fileattr_get0 PROTO ((const char *filename, - const char *attrname)); - -/* This is just a string manipulation function; it does not manipulate - file attributes as such. - - LIST is in the format - - ATTRNAME NAMEVALSEP ATTRVAL {ENTSEP ATTRNAME NAMEVALSEP ATTRVAL} - - And we want to put in an attribute with name NAME and value VAL, - replacing the already-present attribute with name NAME if there is - one. Or if VAL is NULL remove attribute NAME. Return a new - malloc'd list; don't muck with the one passed in. If we are removing - the last attribute return NULL. LIST can be NULL to mean that we - started out without any attributes. - - Examples: - - fileattr_modify ("abc=def", "xxx", "val", '=', ';')) => "abc=def;xxx=val" - fileattr_modify ("abc=def", "abc", "val", '=', ';')) => "abc=val" - fileattr_modify ("abc=v1;def=v2", "abc", "val", '=', ';')) - => "abc=val;def=v2" - fileattr_modify ("abc=v1;def=v2", "def", "val", '=', ';')) - => "abc=v1;def=val" - fileattr_modify ("abc=v1;def=v2", "xxx", "val", '=', ';')) - => "abc=v1;def=v2;xxx=val" - fileattr_modify ("abc=v1;def=v2;ghi=v3", "def", "val", '=', ';')) - => "abc=v1;def=val;ghi=v3" -*/ - -extern char *fileattr_modify PROTO ((char *list, const char *attrname, - const char *attrval, int namevalsep, - int entsep)); - -/* Set attribute ATTRNAME for file FILENAME to ATTRVAL. If ATTRVAL is NULL, - the attribute is removed. Changes are not written to disk until the - next call to fileattr_write. If FILENAME is NULL, set attributes for - files created in the future. If ATTRVAL is NULL, remove that attribute. */ -extern void fileattr_set PROTO ((const char *filename, const char *attrname, - const char *attrval)); - -/* Get all the attributes for file FILENAME. They are returned as malloc'd - data in an unspecified format which is guaranteed only to be good for - passing to fileattr_setall, or NULL if no attributes. If FILENAME is - NULL, get default attributes. */ -extern char *fileattr_getall PROTO ((const char *filename)); - -/* Set the attributes for file FILENAME to ATTRS, overwriting all previous - attributes for that file. ATTRS was obtained from a previous call to - fileattr_getall (malloc'd data or NULL). */ -extern void fileattr_setall PROTO ((const char *filename, const char *attrs)); - -/* Set the attributes for file FILENAME in whatever manner is appropriate - for a newly created file. */ -extern void fileattr_newfile PROTO ((const char *filename)); - -/* Write out all modified attributes. */ -extern void fileattr_write PROTO ((void)); - -/* Free all memory allocated by fileattr_*. */ -extern void fileattr_free PROTO ((void)); - -#define FILEATTR_H 1 -#endif /* fileattr.h */ diff --git a/contrib/cvs/src/filesubr.c b/contrib/cvs/src/filesubr.c deleted file mode 100644 index 1e1f901..0000000 --- a/contrib/cvs/src/filesubr.c +++ /dev/null @@ -1,1100 +0,0 @@ -/* filesubr.c --- subroutines for dealing with files - Jim Blandy <jimb@cyclic.com> - - This file is part of GNU CVS. - - GNU CVS is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -/* These functions were moved out of subr.c because they need different - definitions under operating systems (like, say, Windows NT) with different - file system semantics. */ - -#include <assert.h> -#include "cvs.h" - -#include "xsize.h" - -static int deep_remove_dir PROTO((const char *path)); - -/* - * Copies "from" to "to". - */ -void -copy_file (from, to) - const char *from; - const char *to; -{ - struct stat sb; - struct utimbuf t; - int fdin, fdout; - - if (trace) - (void) fprintf (stderr, "%s-> copy(%s,%s)\n", - CLIENT_SERVER_STR, from, to); - if (noexec) - return; - - /* If the file to be copied is a link or a device, then just create - the new link or device appropriately. */ - if (islink (from)) - { - char *source = xreadlink (from); - symlink (source, to); - free (source); - return; - } - - if (isdevice (from)) - { -#if defined(HAVE_MKNOD) && defined(HAVE_STRUCT_STAT_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 - { - /* Not a link or a device... probably a regular file. */ - if ((fdin = open (from, O_RDONLY)) < 0) - error (1, errno, "cannot open %s for copying", from); - if (fstat (fdin, &sb) < 0) - error (1, errno, "cannot fstat %s", from); - if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0) - error (1, errno, "cannot create %s for copying", to); - if (sb.st_size > 0) - { - char buf[BUFSIZ]; - int n; - - for (;;) - { - n = read (fdin, buf, sizeof(buf)); - if (n == -1) - { -#ifdef EINTR - if (errno == EINTR) - continue; -#endif - error (1, errno, "cannot read file %s for copying", from); - } - else if (n == 0) - break; - - if (write(fdout, buf, n) != n) { - error (1, errno, "cannot write file %s for copying", to); - } - } - -#ifdef HAVE_FSYNC - if (fsync (fdout)) - error (1, errno, "cannot fsync file %s after copying", to); -#endif - } - - if (close (fdin) < 0) - error (0, errno, "cannot close %s", from); - if (close (fdout) < 0) - error (1, errno, "cannot close %s", to); - } - - /* preserve last access & modification times */ - memset ((char *) &t, 0, sizeof (t)); - t.actime = sb.st_atime; - t.modtime = sb.st_mtime; - (void) utime (to, &t); -} - -/* FIXME-krp: these functions would benefit from caching the char * & - stat buf. */ - -/* - * Returns non-zero if the argument file is a directory, or is a symbolic - * link which points to a directory. - */ -int -isdir (file) - const char *file; -{ - struct stat sb; - - if (stat (file, &sb) < 0) - return (0); - return (S_ISDIR (sb.st_mode)); -} - -/* - * Returns non-zero if the argument file is a symbolic link. - */ -int -islink (file) - const char *file; -{ -#ifdef S_ISLNK - struct stat sb; - - if (CVS_LSTAT (file, &sb) < 0) - return (0); - return (S_ISLNK (sb.st_mode)); -#else - return (0); -#endif -} - -/* - * Returns non-zero if the argument file is a block or - * character special device. - */ -int -isdevice (file) - const char *file; -{ - struct stat sb; - - if (CVS_LSTAT (file, &sb) < 0) - return (0); -#ifdef S_ISBLK - if (S_ISBLK (sb.st_mode)) - return 1; -#endif -#ifdef S_ISCHR - if (S_ISCHR (sb.st_mode)) - return 1; -#endif - return 0; -} - -/* - * Returns non-zero if the argument file exists. - */ -int -isfile (file) - const char *file; -{ - return isaccessible(file, F_OK); -} - -/* - * Returns non-zero if the argument file is readable. - */ -int -isreadable (file) - const char *file; -{ - return isaccessible(file, R_OK); -} - -/* - * Returns non-zero if the argument file is writable. - */ -int -iswritable (file) - const char *file; -{ - return isaccessible(file, W_OK); -} - -/* - * Returns non-zero if the argument file is accessable according to - * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid - * bits set. - */ -int -isaccessible (file, mode) - const char *file; - const int mode; -{ -#ifdef SETXID_SUPPORT - struct stat sb; - int umask = 0; - int gmask = 0; - int omask = 0; - int uid, mask; - - if (stat(file, &sb) == -1) - return 0; - if (mode == F_OK) - return 1; - - uid = geteuid(); - if (uid == 0) /* superuser */ - { - if (!(mode & X_OK) || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))) - return 1; - - errno = EACCES; - return 0; - } - - if (mode & R_OK) - { - umask |= S_IRUSR; - gmask |= S_IRGRP; - omask |= S_IROTH; - } - if (mode & W_OK) - { - umask |= S_IWUSR; - gmask |= S_IWGRP; - omask |= S_IWOTH; - } - if (mode & X_OK) - { - umask |= S_IXUSR; - gmask |= S_IXGRP; - omask |= S_IXOTH; - } - - mask = sb.st_uid == uid ? umask : sb.st_gid == getegid() ? gmask : omask; - if ((sb.st_mode & mask) == mask) - return 1; - errno = EACCES; - return 0; -#else - return access(file, mode) == 0; -#endif -} - -/* - * Open a file and die if it fails - */ -FILE * -open_file (name, mode) - const char *name; - const char *mode; -{ - FILE *fp; - - if ((fp = fopen (name, mode)) == NULL) - error (1, errno, "cannot open %s", name); - return (fp); -} - -/* - * Make a directory and die if it fails - */ -void -make_directory (name) - const char *name; -{ - struct stat sb; - - if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode))) - error (0, 0, "%s already exists but is not a directory", name); - if (!noexec && mkdir (name, 0777) < 0) - error (1, errno, "cannot make directory %s", name); -} - -/* - * Make a path to the argument directory, printing a message if something - * goes wrong. - */ -void -make_directories (name) - const char *name; -{ - char *cp; - - if (noexec) - return; - - if (mkdir (name, 0777) == 0 || errno == EEXIST) - return; - if (! existence_error (errno)) - { - error (0, errno, "cannot make path to %s", name); - return; - } - if ((cp = strrchr (name, '/')) == NULL) - return; - *cp = '\0'; - make_directories (name); - *cp++ = '/'; - if (*cp == '\0') - return; - (void) mkdir (name, 0777); -} - -/* Create directory NAME if it does not already exist; fatal error for - other errors. Returns 0 if directory was created; 1 if it already - existed. */ -int -mkdir_if_needed (name) - const char *name; -{ - if (mkdir (name, 0777) < 0) - { - int save_errno = errno; - if (save_errno != EEXIST && !isdir (name)) - error (1, save_errno, "cannot make directory %s", name); - return 1; - } - return 0; -} - -/* - * Change the mode of a file, either adding write permissions, or removing - * all write permissions. Either change honors the current umask setting. - * - * Don't do anything if PreservePermissions is set to `yes'. This may - * have unexpected consequences for some uses of xchmod. - */ -void -xchmod (fname, writable) - const char *fname; - int writable; -{ - struct stat sb; - mode_t mode, oumask; - - if (preserve_perms) - return; - - if (stat (fname, &sb) < 0) - { - if (!noexec) - error (0, errno, "cannot stat %s", fname); - return; - } - oumask = umask (0); - (void) umask (oumask); - if (writable) - { - mode = sb.st_mode | (~oumask - & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0) - | ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0) - | ((sb.st_mode & S_IROTH) ? S_IWOTH : 0))); - } - else - { - mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask; - } - - if (trace) - (void) fprintf (stderr, "%s-> chmod(%s,%o)\n", - CLIENT_SERVER_STR, fname, - (unsigned int) mode); - if (noexec) - return; - - if (chmod (fname, mode) < 0) - error (0, errno, "cannot change mode of file %s", fname); -} - -/* - * Rename a file and die if it fails - */ -void -rename_file (from, to) - const char *from; - const char *to; -{ - if (trace) - (void) fprintf (stderr, "%s-> rename(%s,%s)\n", - CLIENT_SERVER_STR, from, to); - if (noexec) - return; - - if (rename (from, to) < 0) - error (1, errno, "cannot rename file %s to %s", from, to); -} - -/* - * unlink a file, if possible. - */ -int -unlink_file (f) - const char *f; -{ - if (trace) - (void) fprintf (stderr, "%s-> unlink_file(%s)\n", - CLIENT_SERVER_STR, f); - if (noexec) - return (0); - - return (CVS_UNLINK (f)); -} - -/* - * Unlink a file or dir, if possible. If it is a directory do a deep - * removal of all of the files in the directory. Return -1 on error - * (in which case errno is set). - */ -int -unlink_file_dir (f) - const char *f; -{ - struct stat sb; - - /* This is called by the server parent process in contexts where - it is not OK to send output (e.g. after we sent "ok" to the - client). */ - if (trace && !server_active) - (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f); - - if (noexec) - return (0); - - /* For at least some unices, if root tries to unlink() a directory, - instead of doing something rational like returning EISDIR, - the system will gleefully go ahead and corrupt the filesystem. - So we first call stat() to see if it is OK to call unlink(). This - doesn't quite work--if someone creates a directory between the - call to stat() and the call to unlink(), we'll still corrupt - the filesystem. Where is the Unix Haters Handbook when you need - it? */ - if (stat (f, &sb) < 0) - { - if (existence_error (errno)) - { - /* The file or directory doesn't exist anyhow. */ - return -1; - } - } - else if (S_ISDIR (sb.st_mode)) - return deep_remove_dir (f); - - return CVS_UNLINK (f); -} - -/* Remove a directory and everything it contains. Returns 0 for - * success, -1 for failure (in which case errno is set). - */ - -static int -deep_remove_dir (path) - const char *path; -{ - DIR *dirp; - struct dirent *dp; - - if (rmdir (path) != 0) - { - if (errno == ENOTEMPTY - || errno == EEXIST - /* Ugly workaround for ugly AIX 4.1 (and 3.2) header bug - (it defines ENOTEMPTY and EEXIST to 17 but actually - returns 87). */ - || (ENOTEMPTY == 17 && EEXIST == 17 && errno == 87)) - { - if ((dirp = CVS_OPENDIR (path)) == NULL) - /* If unable to open the directory return - * an error - */ - return -1; - - errno = 0; - while ((dp = CVS_READDIR (dirp)) != NULL) - { - char *buf; - - if (strcmp (dp->d_name, ".") == 0 || - strcmp (dp->d_name, "..") == 0) - continue; - - buf = xmalloc (strlen (path) + strlen (dp->d_name) + 5); - sprintf (buf, "%s/%s", path, dp->d_name); - - /* See comment in unlink_file_dir explanation of why we use - isdir instead of just calling unlink and checking the - status. */ - if (isdir(buf)) - { - if (deep_remove_dir(buf)) - { - CVS_CLOSEDIR(dirp); - free (buf); - return -1; - } - } - else - { - if (CVS_UNLINK (buf) != 0) - { - CVS_CLOSEDIR(dirp); - free (buf); - return -1; - } - } - free (buf); - - errno = 0; - } - if (errno != 0) - { - int save_errno = errno; - CVS_CLOSEDIR (dirp); - errno = save_errno; - return -1; - } - CVS_CLOSEDIR (dirp); - return rmdir (path); - } - else - return -1; - } - - /* Was able to remove the directory return 0 */ - return 0; -} - -/* Read NCHARS bytes from descriptor FD into BUF. - Return the number of characters successfully read. - The number returned is always NCHARS unless end-of-file or error. */ -static size_t -block_read (fd, buf, nchars) - int fd; - char *buf; - size_t nchars; -{ - char *bp = buf; - size_t nread; - - do - { - nread = read (fd, bp, nchars); - if (nread == (size_t)-1) - { -#ifdef EINTR - if (errno == EINTR) - continue; -#endif - return (size_t)-1; - } - - if (nread == 0) - break; - - bp += nread; - nchars -= nread; - } while (nchars != 0); - - return bp - buf; -} - - -/* - * Compare "file1" to "file2". Return non-zero if they don't compare exactly. - * If FILE1 and FILE2 are special files, compare their salient characteristics - * (i.e. major/minor device numbers, links, etc. - */ -int -xcmp (file1, file2) - const char *file1; - const char *file2; -{ - char *buf1, *buf2; - struct stat sb1, sb2; - int fd1, fd2; - int ret; - - if (CVS_LSTAT (file1, &sb1) < 0) - error (1, errno, "cannot lstat %s", file1); - if (CVS_LSTAT (file2, &sb2) < 0) - error (1, errno, "cannot lstat %s", file2); - - /* If FILE1 and FILE2 are not the same file type, they are unequal. */ - if ((sb1.st_mode & S_IFMT) != (sb2.st_mode & S_IFMT)) - return 1; - - /* If FILE1 and FILE2 are symlinks, they are equal if they point to - the same thing. */ -#ifdef S_ISLNK - if (S_ISLNK (sb1.st_mode) && S_ISLNK (sb2.st_mode)) - { - int result; - buf1 = xreadlink (file1); - buf2 = xreadlink (file2); - result = (strcmp (buf1, buf2) == 0); - free (buf1); - free (buf2); - return result; - } -#endif - - /* If FILE1 and FILE2 are devices, they are equal if their device - numbers match. */ - if (S_ISBLK (sb1.st_mode) || S_ISCHR (sb1.st_mode)) - { -#ifdef HAVE_STRUCT_STAT_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) - error (1, errno, "cannot open file %s for comparing", file1); - if ((fd2 = open (file2, O_RDONLY)) < 0) - error (1, errno, "cannot open file %s for comparing", file2); - - /* A generic file compare routine might compare st_dev & st_ino here - to see if the two files being compared are actually the same file. - But that won't happen in CVS, so we won't bother. */ - - if (sb1.st_size != sb2.st_size) - ret = 1; - else if (sb1.st_size == 0) - ret = 0; - else - { - /* FIXME: compute the optimal buffer size by computing the least - common multiple of the files st_blocks field */ - size_t buf_size = 8 * 1024; - size_t read1; - size_t read2; - - buf1 = xmalloc (buf_size); - buf2 = xmalloc (buf_size); - - do - { - read1 = block_read (fd1, buf1, buf_size); - if (read1 == (size_t)-1) - error (1, errno, "cannot read file %s for comparing", file1); - - read2 = block_read (fd2, buf2, buf_size); - if (read2 == (size_t)-1) - error (1, errno, "cannot read file %s for comparing", file2); - - /* assert (read1 == read2); */ - - ret = memcmp(buf1, buf2, read1); - } while (ret == 0 && read1 == buf_size); - - free (buf1); - free (buf2); - } - - (void) close (fd1); - (void) close (fd2); - return (ret); -} - -/* Generate a unique temporary filename. Returns a pointer to a newly - * malloc'd string containing the name. Returns successfully or not at - * all. - * - * THIS FUNCTION IS DEPRECATED!!! USE cvs_temp_file INSTEAD!!! - * - * and yes, I know about the way the rcs commands use temp files. I think - * they should be converted too but I don't have time to look into it right - * now. - */ -char * -cvs_temp_name () -{ - char *fn; - FILE *fp; - - fp = cvs_temp_file (&fn); - if (fp == NULL) - error (1, errno, "Failed to create temporary file %s", - fn ? fn : "(null)"); - if (fclose (fp) == EOF) - error (0, errno, "Failed to close temporary file %s", fn); - return fn; -} - -/* Generate a unique temporary filename and return an open file stream - * to the truncated file by that name - * - * INPUTS - * filename where to place the pointer to the newly allocated file - * name string - * - * OUTPUTS - * filename dereferenced, will point to the newly allocated file - * name string. This value is undefined if the function - * returns an error. - * - * RETURNS - * An open file pointer to a read/write mode empty temporary file with the - * unique file name or NULL on failure. - * - * ERRORS - * on error, errno will be set to some value either by CVS_FOPEN or - * whatever system function is called to generate the temporary file name - */ -/* There are at least four functions for generating temporary - * filenames. We use mkstemp (BSD 4.3) if possible, else tempnam (SVID 3), - * else mktemp (BSD 4.3), and as last resort tmpnam (POSIX). Reason is that - * mkstemp, tempnam, and mktemp both allow to specify the directory in which - * the temporary file will be created. - * - * And the _correct_ way to use the deprecated functions probably involves - * opening file descriptors using O_EXCL & O_CREAT and even doing the annoying - * NFS locking thing, but until I hear of more problems, I'm not going to - * bother. - */ -FILE * -cvs_temp_file (filename) - char **filename; -{ - char *fn; - FILE *fp; - - /* FIXME - I'd like to be returning NULL here in noexec mode, but I think - * some of the rcs & diff functions which rely on a temp file run in - * noexec mode too. - */ - - assert (filename != NULL); - -#ifdef HAVE_MKSTEMP - - { - int fd; - - fn = xmalloc (strlen (Tmpdir) + 11); - sprintf (fn, "%s/%s", Tmpdir, "cvsXXXXXX" ); - fd = mkstemp (fn); - - /* a NULL return will be interpreted by callers as an error and - * errno should still be set - */ - if (fd == -1) fp = NULL; - else if ((fp = CVS_FDOPEN (fd, "w+")) == NULL) - { - /* Attempt to close and unlink the file since mkstemp returned - * sucessfully and we believe it's been created and opened. - */ - int save_errno = errno; - if (close (fd)) - error (0, errno, "Failed to close temporary file %s", fn); - if (CVS_UNLINK (fn)) - error (0, errno, "Failed to unlink temporary file %s", fn); - errno = save_errno; - } - - if (fp == NULL) - { - free (fn); - fn = NULL; - } - /* mkstemp is defined to open mode 0600 using glibc 2.0.7+ */ - /* FIXME - configure can probably tell us which version of glibc we are - * linking to and not chmod for 2.0.7+ - */ - else chmod (fn, 0600); - - } - -#elif HAVE_TEMPNAM - - /* tempnam has been deprecated due to under-specification */ - - fn = tempnam (Tmpdir, "cvs"); - if (fn == NULL) fp = NULL; - else if ((fp = CVS_FOPEN (fn, "w+")) == NULL) - { - free (fn); - fn = NULL; - } - else chmod (fn, 0600); - - /* tempnam returns a pointer to a newly malloc'd string, so there's - * no need for a xstrdup - */ - -#elif HAVE_MKTEMP - - /* mktemp has been deprecated due to the BSD 4.3 specification specifying - * that XXXXXX will be replaced by a PID and a letter, creating only 26 - * possibilities, a security risk, and a race condition. - */ - - { - char *ifn; - - ifn = xmalloc (strlen (Tmpdir) + 11); - sprintf (ifn, "%s/%s", Tmpdir, "cvsXXXXXX" ); - fn = mktemp (ifn); - - if (fn == NULL) fp = NULL; - else fp = CVS_FOPEN (fn, "w+"); - - if (fp == NULL) free (ifn); - else chmod (fn, 0600); - - } - -#else /* use tmpnam if all else fails */ - - /* tmpnam is deprecated */ - - { - char ifn[L_tmpnam + 1]; - - fn = tmpnam (ifn); - - if (fn == NULL) fp = NULL; - else if ((fp = CVS_FOPEN (ifn, "w+")) != NULL) - { - fn = xstrdup (ifn); - chmod (fn, 0600); - } - - } - -#endif - - *filename = fn; - if (fn == NULL && fp != NULL) - { - fclose (fp); - fp = NULL; - } - return fp; -} - - - -#ifdef HAVE_READLINK -/* char * - * xreadlink ( const char *link ) - * - * Like the X/OPEN and 4.4BSD readlink() function, but allocates and returns - * its own buf. - * - * INPUTS - * link The original path. - * - * RETURNS - * The resolution of the final symbolic link in the path. - * - * ERRORS - * This function exits with a fatal error if it fails to read the link for - * any reason. - */ -#define MAXSIZE (SIZE_MAX < SSIZE_MAX ? SIZE_MAX : SSIZE_MAX) - -char * -xreadlink (link) - const char *link; -{ - char *file = NULL; - size_t buflen = BUFSIZ; - - /* Get the name of the file to which `from' is linked. */ - while (1) - { - ssize_t r; - size_t link_name_len; - - file = xrealloc (file, buflen); - r = readlink (link, file, buflen); - link_name_len = r; - - if (r < 0 -#ifdef ERANGE - /* AIX 4 and HP-UX report ERANGE if the buffer is too small. */ - && errno != ERANGE -#endif - ) - error (1, errno, "cannot readlink %s", link); - - /* If there is space for the NUL byte, set it and return. */ - if (r >= 0 && link_name_len < buflen) - { - file[link_name_len] = '\0'; - return file; - } - - if (buflen <= MAXSIZE / 2) - buflen *= 2; - else if (buflen < MAXSIZE) - buflen = MAXSIZE; - else - /* Our buffer cannot grow any bigger. */ - error (1, ENAMETOOLONG, "cannot readlink %s", link); - } -} -#endif /* HAVE_READLINK */ - - - -/* char * - * xresolvepath ( const char *path ) - * - * Like xreadlink(), but resolve all links in a path. - * - * INPUTS - * path The original path. - * - * RETURNS - * The path with any symbolic links expanded. - * - * ERRORS - * This function exits with a fatal error if it fails to read the link for - * any reason. - */ -char * -xresolvepath ( path ) - const char *path; -{ - char *hardpath; - char *owd; - - assert ( isdir ( path ) ); - - /* FIXME - If HAVE_READLINK is defined, we should probably walk the path - * bit by bit calling xreadlink(). - */ - - owd = xgetwd(); - if ( CVS_CHDIR ( path ) < 0) - error ( 1, errno, "cannot chdir to %s", path ); - if ( ( hardpath = xgetwd() ) == NULL ) - error (1, errno, "cannot getwd in %s", path); - if ( CVS_CHDIR ( owd ) < 0) - error ( 1, errno, "cannot chdir to %s", owd ); - free (owd); - return hardpath; -} - - - -/* Return a pointer into PATH's last component. */ -const char * -last_component (path) - const char *path; -{ - const char *last = strrchr (path, '/'); - - assert (path); - if (last && (last != path)) - return last + 1; - else - return path; -} - -/* Return the home directory. Returns a pointer to storage - managed by this function or its callees (currently getenv). - This function will return the same thing every time it is - called. Returns NULL if there is no home directory. - - Note that for a pserver server, this may return root's home - directory. What typically happens is that upon being started from - inetd, before switching users, the code in cvsrc.c calls - get_homedir which remembers root's home directory in the static - variable. Then the switch happens and get_homedir might return a - directory that we don't even have read or execute permissions for - (which is bad, when various parts of CVS try to read there). One - fix would be to make the value returned by get_homedir only good - until the next call (which would free the old value). Another fix - would be to just always malloc our answer, and let the caller free - it (that is best, because some day we may need to be reentrant). - - The workaround is to put -f in inetd.conf which means that - get_homedir won't get called until after the switch in user ID. - - The whole concept of a "home directory" on the server is pretty - iffy, although I suppose some people probably are relying on it for - .cvsrc and such, in the cases where it works. */ -char * -get_homedir () -{ - static char *home = NULL; - char *env; - struct passwd *pw; - - if (home != NULL) - return home; - - if (!server_active && (env = getenv ("HOME")) != NULL) - home = env; - else if ((pw = (struct passwd *) getpwuid (getuid ())) - && pw->pw_dir) - home = xstrdup (pw->pw_dir); - else - return 0; - - return home; -} - -/* Compose a path to a file in the home directory. This is necessary because - * of different behavior on UNIX and VMS. See the notes in vms/filesubr.c. - * - * A more clean solution would be something more along the lines of a - * "join a directory to a filename" kind of thing which was not specific to - * the homedir. This should aid portability between UNIX, Mac, Windows, VMS, - * and possibly others. This is already handled by Perl - it might be - * interesting to see how much of the code was written in C since Perl is under - * the GPL and the Artistic license - we might be able to use it. - */ -char * -strcat_filename_onto_homedir (dir, file) - const char *dir; - const char *file; -{ - char *path = xmalloc (strlen (dir) + 1 + strlen(file) + 1); - sprintf (path, "%s/%s", dir, file); - return path; -} - -/* See cvs.h for description. On unix this does nothing, because the - shell expands the wildcards. */ -void -expand_wild (argc, argv, pargc, pargv) - int argc; - char **argv; - int *pargc; - char ***pargv; -{ - int i; - assert (argv || !argc); - if (size_overflow_p (xtimes (argc, sizeof (char *)))) { - *pargc = 0; - *pargv = NULL; - error (0, 0, "expand_wild: too many arguments"); - return; - } - *pargc = argc; - *pargv = xmalloc (xtimes (argc, sizeof (char *))); - for (i = 0; i < argc; ++i) - (*pargv)[i] = xstrdup (argv[i]); -} - - - -#ifdef SERVER_SUPPORT -/* Case-insensitive string compare. I know that some systems - have such a routine, but I'm not sure I see any reasons for - dealing with the hair of figuring out whether they do (I haven't - looked into whether this is a performance bottleneck; I would guess - not). */ -int -cvs_casecmp (str1, str2) - const char *str1; - const char *str2; -{ - const char *p; - const char *q; - int pqdiff; - - p = str1; - q = str2; - while ((pqdiff = tolower (*p) - tolower (*q)) == 0) - { - if (*p == '\0') - return 0; - ++p; - ++q; - } - return pqdiff; -} -#endif /* SERVER_SUPPORT */ diff --git a/contrib/cvs/src/find_names.c b/contrib/cvs/src/find_names.c deleted file mode 100644 index 5bfd895..0000000 --- a/contrib/cvs/src/find_names.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Find Names - * - * Finds all the pertinent file names, both from the administration and from the - * repository - * - * Find Dirs - * - * Finds all pertinent sub-directories of the checked out instantiation and the - * repository (and optionally the attic) - */ - -#include "cvs.h" - -static int find_dirs PROTO((char *dir, List * list, int checkadm, - List *entries)); -static int find_rcs PROTO((char *dir, List * list)); -static int add_subdir_proc PROTO((Node *, void *)); -static int register_subdir_proc PROTO((Node *, void *)); - -/* - * add the key from entry on entries list to the files list - */ -static int add_entries_proc PROTO((Node *, void *)); -static int -add_entries_proc (node, closure) - Node *node; - void *closure; -{ - Node *fnode; - List *filelist = closure; - Entnode *entnode = node->data; - - if (entnode->type != ENT_FILE) - return (0); - - fnode = getnode (); - fnode->type = FILES; - fnode->key = xstrdup (node->key); - if (addnode (filelist, fnode) != 0) - freenode (fnode); - return (0); -} - -/* Find files in the repository and/or working directory. On error, - may either print a nonfatal error and return NULL, or just give - a fatal error. On success, return non-NULL (even if it is an empty - list). */ - -List * -Find_Names (repository, which, aflag, optentries) - char *repository; - int which; - int aflag; - List **optentries; -{ - List *entries; - List *files; - - /* make a list for the files */ - files = getlist (); - - /* look at entries (if necessary) */ - if (which & W_LOCAL) - { - /* parse the entries file (if it exists) */ - entries = Entries_Open (aflag, NULL); - if (entries != NULL) - { - /* walk the entries file adding elements to the files list */ - (void) walklist (entries, add_entries_proc, files); - - /* if our caller wanted the entries list, return it; else free it */ - if (optentries != NULL) - *optentries = entries; - else - Entries_Close (entries); - } - } - - if ((which & W_REPOS) && repository && !isreadable (CVSADM_ENTSTAT)) - { - /* search the repository */ - if (find_rcs (repository, files) != 0) - { - error (0, errno, "cannot open directory %s", repository); - goto error_exit; - } - - /* search the attic too */ - if (which & W_ATTIC) - { - char *dir; - dir = xmalloc (strlen (repository) + sizeof (CVSATTIC) + 10); - (void) sprintf (dir, "%s/%s", repository, CVSATTIC); - if (find_rcs (dir, files) != 0 - && !existence_error (errno)) - /* For now keep this a fatal error, seems less useful - for access control than the case above. */ - error (1, errno, "cannot open directory %s", dir); - free (dir); - } - } - - /* sort the list into alphabetical order and return it */ - sortlist (files, fsortcmp); - return (files); - error_exit: - dellist (&files); - return NULL; -} - -/* - * Add an entry from the subdirs list to the directories list. This - * is called via walklist. - */ - -static int -add_subdir_proc (p, closure) - Node *p; - void *closure; -{ - List *dirlist = closure; - Entnode *entnode = p->data; - Node *dnode; - - if (entnode->type != ENT_SUBDIR) - return 0; - - dnode = getnode (); - dnode->type = DIRS; - dnode->key = xstrdup (entnode->user); - if (addnode (dirlist, dnode) != 0) - freenode (dnode); - return 0; -} - -/* - * Register a subdirectory. This is called via walklist. - */ - -/*ARGSUSED*/ -static int -register_subdir_proc (p, closure) - Node *p; - void *closure; -{ - List *entries = (List *) closure; - - Subdir_Register (entries, (char *) NULL, p->key); - return 0; -} - -/* - * create a list of directories to traverse from the current directory - */ -List * -Find_Directories (repository, which, entries) - char *repository; - int which; - List *entries; -{ - List *dirlist; - - /* make a list for the directories */ - dirlist = getlist (); - - /* find the local ones */ - if (which & W_LOCAL) - { - List *tmpentries; - struct stickydirtag *sdtp; - - /* Look through the Entries file. */ - - if (entries != NULL) - tmpentries = entries; - else if (isfile (CVSADM_ENT)) - tmpentries = Entries_Open (0, NULL); - else - tmpentries = NULL; - - if (tmpentries != NULL) - sdtp = tmpentries->list->data; - - /* If we do have an entries list, then if sdtp is NULL, or if - sdtp->subdirs is nonzero, all subdirectory information is - recorded in the entries list. */ - if (tmpentries != NULL && (sdtp == NULL || sdtp->subdirs)) - walklist (tmpentries, add_subdir_proc, (void *) dirlist); - else - { - /* This is an old working directory, in which subdirectory - information is not recorded in the Entries file. Find - the subdirectories the hard way, and, if possible, add - it to the Entries file for next time. */ - - /* FIXME-maybe: find_dirs is bogus for this usage because - it skips CVSATTIC and CVSLCK directories--those names - should be special only in the repository. However, in - the interests of not perturbing this code, we probably - should leave well enough alone unless we want to write - a sanity.sh test case (which would operate by manually - hacking on the CVS/Entries file). */ - - if (find_dirs (".", dirlist, 1, tmpentries) != 0) - error (1, errno, "cannot open current directory"); - if (tmpentries != NULL) - { - if (! list_isempty (dirlist)) - walklist (dirlist, register_subdir_proc, - (void *) tmpentries); - else - Subdirs_Known (tmpentries); - } - } - - if (entries == NULL && tmpentries != NULL) - Entries_Close (tmpentries); - } - - /* look for sub-dirs in the repository */ - if ((which & W_REPOS) && repository) - { - /* search the repository */ - if (find_dirs (repository, dirlist, 0, entries) != 0) - error (1, errno, "cannot open directory %s", repository); - - /* We don't need to look in the attic because directories - never go in the attic. In the future, there hopefully will - be a better mechanism for detecting whether a directory in - the repository is alive or dead; it may or may not involve - moving directories to the attic. */ - } - - /* sort the list into alphabetical order and return it */ - sortlist (dirlist, fsortcmp); - return (dirlist); -} - -/* - * Finds all the ,v files in the argument directory, and adds them to the - * files list. Returns 0 for success and non-zero if the argument directory - * cannot be opened, in which case errno is set to indicate the error. - * In the error case LIST is left in some reasonable state (unchanged, or - * containing the files which were found before the error occurred). - */ -static int -find_rcs (dir, list) - char *dir; - List *list; -{ - Node *p; - struct dirent *dp; - DIR *dirp; - - /* set up to read the dir */ - if ((dirp = CVS_OPENDIR (dir)) == NULL) - return (1); - - /* read the dir, grabbing the ,v files */ - errno = 0; - while ((dp = CVS_READDIR (dirp)) != NULL) - { - if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0) - { - char *comma; - - comma = strrchr (dp->d_name, ','); /* strip the ,v */ - *comma = '\0'; - p = getnode (); - p->type = FILES; - p->key = xstrdup (dp->d_name); - if (addnode (list, p) != 0) - freenode (p); - } - errno = 0; - } - if (errno != 0) - { - int save_errno = errno; - (void) CVS_CLOSEDIR (dirp); - errno = save_errno; - return 1; - } - (void) CVS_CLOSEDIR (dirp); - return (0); -} - -/* - * Finds all the subdirectories of the argument dir and adds them to - * the specified list. Sub-directories without a CVS administration - * directory are optionally ignored. If ENTRIES is not NULL, all - * files on the list are ignored. Returns 0 for success or 1 on - * error, in which case errno is set to indicate the error. - */ -static int -find_dirs (dir, list, checkadm, entries) - char *dir; - List *list; - int checkadm; - List *entries; -{ - Node *p; - char *tmp = NULL; - size_t tmp_size = 0; - struct dirent *dp; - DIR *dirp; - int skip_emptydir = 0; - - /* First figure out whether we need to skip directories named - Emptydir. Except in the CVSNULLREPOS case, Emptydir is just - a normal directory name. */ - if (isabsolute (dir) - && strncmp (dir, current_parsed_root->directory, strlen (current_parsed_root->directory)) == 0 - && ISDIRSEP (dir[strlen (current_parsed_root->directory)]) - && strcmp (dir + strlen (current_parsed_root->directory) + 1, CVSROOTADM) == 0) - skip_emptydir = 1; - - /* set up to read the dir */ - if ((dirp = CVS_OPENDIR (dir)) == NULL) - return (1); - - /* read the dir, grabbing sub-dirs */ - errno = 0; - while ((dp = CVS_READDIR (dirp)) != NULL) - { - if (strcmp (dp->d_name, ".") == 0 || - strcmp (dp->d_name, "..") == 0 || - strcmp (dp->d_name, CVSATTIC) == 0 || - strcmp (dp->d_name, CVSLCK) == 0 || - strcmp (dp->d_name, CVSREP) == 0) - goto do_it_again; - - /* findnode() is going to be significantly faster than stat() - because it involves no system calls. That is why we bother - with the entries argument, and why we check this first. */ - if (entries != NULL && findnode (entries, dp->d_name) != NULL) - goto do_it_again; - - if (skip_emptydir - && strcmp (dp->d_name, CVSNULLREPOS) == 0) - goto do_it_again; - -#ifdef DT_DIR - if (dp->d_type != DT_DIR) - { - if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK) - goto do_it_again; -#endif - /* don't bother stating ,v files */ - if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0) - goto do_it_again; - - expand_string (&tmp, - &tmp_size, - strlen (dir) + strlen (dp->d_name) + 10); - sprintf (tmp, "%s/%s", dir, dp->d_name); - if (!isdir (tmp)) - goto do_it_again; - -#ifdef DT_DIR - } -#endif - - /* check for administration directories (if needed) */ - if (checkadm) - { - /* blow off symbolic links to dirs in local dir */ -#ifdef DT_DIR - if (dp->d_type != DT_DIR) - { - /* we're either unknown or a symlink at this point */ - if (dp->d_type == DT_LNK) - goto do_it_again; -#endif - /* Note that we only get here if we already set tmp - above. */ - if (islink (tmp)) - goto do_it_again; -#ifdef DT_DIR - } -#endif - - /* check for new style */ - expand_string (&tmp, - &tmp_size, - (strlen (dir) + strlen (dp->d_name) - + sizeof (CVSADM) + 10)); - (void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM); - if (!isdir (tmp)) - goto do_it_again; - } - - /* put it in the list */ - p = getnode (); - p->type = DIRS; - p->key = xstrdup (dp->d_name); - if (addnode (list, p) != 0) - freenode (p); - - do_it_again: - errno = 0; - } - if (errno != 0) - { - int save_errno = errno; - (void) CVS_CLOSEDIR (dirp); - errno = save_errno; - return 1; - } - (void) CVS_CLOSEDIR (dirp); - if (tmp != NULL) - free (tmp); - return (0); -} diff --git a/contrib/cvs/src/hardlink.c b/contrib/cvs/src/hardlink.c deleted file mode 100644 index ed05033..0000000 --- a/contrib/cvs/src/hardlink.c +++ /dev/null @@ -1,307 +0,0 @@ -/* This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -/* Collect and manage hardlink info associated with a particular file. */ - -#include "cvs.h" - -#ifdef PRESERVE_PERMISSIONS_SUPPORT -# include "hardlink.h" - -/* The structure currently used to manage hardlink info is a list. - Therefore, most of the functions which manipulate hardlink data - are walklist procedures. This is not a very efficient implementation; - if someone decides to use a real hash table (for instance), then - much of this code can be rewritten to be a little less arcane. - - Each element of `hardlist' represents an inode. It is keyed on the - inode number, and points to a list of files. This is to make it - easy to find out what files are linked to a given file FOO: find - FOO's inode, look it up in hardlist, and retrieve the list of files - associated with that inode. - - Each file node, in turn, is represented by a `hardlink_info' struct, - which includes `status' and `links' fields. The `status' field should - be used by a procedure like commit_fileproc or update_fileproc to - record each file's status; that way, after all file links have been - recorded, CVS can check the linkage of files which are in doubt - (i.e. T_NEEDS_MERGE files). - - TODO: a diagram of an example hardlist would help here. */ - -/* TODO: change this to something with a marginal degree of - efficiency, like maybe a hash table. Yeah. */ - -List *hardlist; /* Record hardlink information for working files */ -char *working_dir; /* The top-level working directory, used for - constructing full pathnames. */ - -/* Return a pointer to FILEPATH's node in the hardlist. This means - looking up its inode, retrieving the list of files linked to that - inode, and then looking up FILE in that list. If the file doesn't - seem to exist, return NULL. */ -Node * -lookup_file_by_inode (filepath) - const char *filepath; -{ - char *inodestr, *file; - struct stat sb; - Node *hp, *p; - - /* Get file's basename, so that we can stat it. */ - file = strrchr (filepath, '/'); - if (file) - ++file; - else - file = (char *) 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) + 1); - if (stat (file, &sb) < 0) - { - if (existence_error (errno)) - { - /* The file doesn't exist; we may be doing an update on a - file that's been removed. A nonexistent file has no - link information, so return without changing hardlist. */ - free (inodestr); - return NULL; - } - error (1, errno, "cannot stat %s", file); - } - - sprintf (inodestr, "%lx", (unsigned long) sb.st_ino); - - /* Find out if this inode is already in the hardlist, adding - a new entry to the list if not. */ - hp = findnode (hardlist, inodestr); - if (hp == NULL) - { - hp = getnode (); - hp->type = NT_UNKNOWN; - hp->key = inodestr; - hp->data = getlist(); - hp->delproc = dellist; - (void) addnode (hardlist, hp); - } - else - { - free (inodestr); - } - - p = findnode (hp->data, filepath); - if (p == NULL) - { - p = getnode(); - p->type = NT_UNKNOWN; - p->key = xstrdup (filepath); - p->data = NULL; - (void) addnode (hp->data, p); - } - - return p; -} - -/* After a file has been checked out, add a node for it to the hardlist - (if necessary) and mark it as checked out. */ -void -update_hardlink_info (file) - const char *file; -{ - char *path; - Node *n; - struct hardlink_info *hlinfo; - - if (file[0] == '/') - { - path = xstrdup (file); - } - else - { - /* file is a relative pathname; assume it's from the current - working directory. */ - char *dir = xgetwd(); - path = xmalloc (strlen(dir) + strlen(file) + 2); - sprintf (path, "%s/%s", dir, file); - free (dir); - } - - n = lookup_file_by_inode (path); - if (n == NULL) - { - /* Something is *really* wrong if the file doesn't exist here; - update_hardlink_info should be called only when a file has - just been checked out to a working directory. */ - error (1, 0, "lost hardlink info for %s", file); - } - - if (n->data == NULL) - n->data = xmalloc (sizeof (struct hardlink_info)); - hlinfo = n->data; - hlinfo->status = T_UPTODATE; - hlinfo->checked_out = 1; -} - -/* Return a List with all the files known to be linked to FILE in - the working directory. Used by special_file_mismatch, to determine - whether it is safe to merge two files. - - FIXME: What is the memory allocation for the return value? We seem - to sometimes allocate a new list (getlist() call below) and sometimes - return an existing list (where we return n->data). */ -List * -list_linked_files_on_disk (file) - char *file; -{ - char *inodestr, *path; - struct stat sb; - Node *n; - - /* If hardlist is NULL, we have not been doing an operation that - would permit us to know anything about the file's hardlinks - (cvs update, cvs commit, etc). Return an empty list. */ - if (hardlist == NULL) - return getlist(); - - /* Get the full pathname of file (assuming the working directory) */ - if (file[0] == '/') - path = xstrdup (file); - else - { - char *dir = xgetwd(); - path = (char *) xmalloc (strlen(dir) + strlen(file) + 2); - sprintf (path, "%s/%s", dir, file); - free (dir); - } - - /* We do an extra lookup_file here just to make sure that there - is a node for `path' in the hardlist. If that were not so, - comparing the working directory linkage against the repository - linkage for a file would always fail. */ - (void) lookup_file_by_inode (path); - - if (stat (path, &sb) < 0) - error (1, errno, "cannot stat %s", 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) + 1); - sprintf (inodestr, "%lx", (unsigned long) sb.st_ino); - - /* Make sure the files linked to this inode are sorted. */ - n = findnode (hardlist, inodestr); - sortlist (n->data, fsortcmp); - - free (inodestr); - return n->data; -} - -/* Compare the files in the `key' fields of two lists, returning 1 if - the lists are equivalent and 0 otherwise. - - Only the basenames of each file are compared. This is an awful hack - that exists because list_linked_files_on_disk returns full paths - and the `hardlinks' structure of a RCSVers node contains only - basenames. That in turn is a result of the awful hack that only - basenames are stored in the RCS file. If anyone ever solves the - problem of correctly managing cross-directory hardlinks, this - function (along with most functions in this file) must be fixed. */ - -int -compare_linkage_lists (links1, links2) - List *links1; - List *links2; -{ - Node *n1, *n2; - char *p1, *p2; - - sortlist (links1, fsortcmp); - sortlist (links2, fsortcmp); - - n1 = links1->list->next; - n2 = links2->list->next; - - while (n1 != links1->list && n2 != links2->list) - { - /* Get the basenames of both files. */ - p1 = strrchr (n1->key, '/'); - if (p1 == NULL) - p1 = n1->key; - else - ++p1; - - p2 = strrchr (n2->key, '/'); - if (p2 == NULL) - p2 = n2->key; - else - ++p2; - - /* Compare the files' basenames. */ - if (strcmp (p1, p2) != 0) - return 0; - - n1 = n1->next; - n2 = n2->next; - } - - /* At this point we should be at the end of both lists; if not, - one file has more links than the other, and return 1. */ - return (n1 == links1->list && n2 == links2->list); -} - -/* Find a checked-out file in a list of filenames. Used by RCS_checkout - when checking out a new hardlinked file, to decide whether this file - can be linked to any others that already exist. The return value - is not currently used. */ - -int -find_checkedout_proc (node, data) - Node *node; - void *data; -{ - Node **uptodate = (Node **) data; - Node *link; - char *dir = xgetwd(); - char *path; - struct hardlink_info *hlinfo; - - /* If we have already found a file, don't do anything. */ - if (*uptodate != NULL) - return 0; - - /* 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 (strlen (dir) + strlen (node->key) + 2); - sprintf (path, "%s/%s", dir, node->key); - link = lookup_file_by_inode (path); - free (path); - free (dir); - - if (link == NULL) - { - /* We haven't seen this file -- maybe it hasn't been checked - out yet at all. */ - return 0; - } - - hlinfo = link->data; - if (hlinfo->checked_out) - { - /* This file has been checked out recently, so it's safe to - link to it. */ - *uptodate = link; - } - - return 0; -} -#endif /* PRESERVE_PERMISSIONS_SUPPORT */ diff --git a/contrib/cvs/src/hardlink.h b/contrib/cvs/src/hardlink.h deleted file mode 100644 index b227968..0000000 --- a/contrib/cvs/src/hardlink.h +++ /dev/null @@ -1,35 +0,0 @@ -/* This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -/* Data type definitions and declarations for hardlink management. */ - -/* This file should be #included in CVS source files after cvs.h - since it relies on types and macros defined there. */ - -/* The `checked_out' member of a hardlink_info struct is used only - when files are being checked out or updated. It is used only when - hardlinked files are being checked out. */ - -#ifdef PRESERVE_PERMISSIONS_SUPPORT -struct hardlink_info -{ - Ctype status; /* as returned from Classify_File() */ - int checked_out; /* has this file been checked out lately? */ -}; - -extern List *hardlist; -extern char *working_dir; - -Node *lookup_file_by_inode PROTO ((const char *)); -void update_hardlink_info PROTO ((const char *)); -List *list_linked_files_on_disk PROTO ((char *)); -int compare_linkage_lists PROTO ((List *, List *)); -int find_checkedout_proc PROTO ((Node *, void *)); -#endif /* PRESERVE_PERMISSIONS_SUPPORT */ diff --git a/contrib/cvs/src/hash.c b/contrib/cvs/src/hash.c deleted file mode 100644 index d9bc12c..0000000 --- a/contrib/cvs/src/hash.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Polk's hash list manager. So cool. - */ - -#include "cvs.h" -#include <assert.h> - -/* Global caches. The idea is that we maintain a linked list of "free"d - nodes or lists, and get new items from there. It has been suggested - to use an obstack instead, but off the top of my head, I'm not sure - that would gain enough to be worth worrying about. */ -static List *listcache = NULL; -static Node *nodecache = NULL; - -static void freenode_mem PROTO((Node * p)); - -/* hash function */ -static int -hashp (key) - const char *key; -{ - unsigned int h = 0; - unsigned int g; - - assert(key != NULL); - - while (*key != 0) - { - unsigned int c = *key++; - /* The FOLD_FN_CHAR is so that findnode_fn works. */ - h = (h << 4) + FOLD_FN_CHAR (c); - if ((g = h & 0xf0000000) != 0) - h = (h ^ (g >> 24)) ^ g; - } - - return (h % HASHSIZE); -} - -/* - * create a new list (or get an old one from the cache) - */ -List * -getlist () -{ - int i; - List *list; - Node *node; - - if (listcache != NULL) - { - /* get a list from the cache and clear it */ - list = listcache; - listcache = listcache->next; - list->next = (List *) NULL; - for (i = 0; i < HASHSIZE; i++) - list->hasharray[i] = (Node *) NULL; - } - else - { - /* make a new list from scratch */ - list = (List *) xmalloc (sizeof (List)); - memset ((char *) list, 0, sizeof (List)); - node = getnode (); - list->list = node; - node->type = HEADER; - node->next = node->prev = node; - } - return (list); -} - -/* - * free up a list - */ -void -dellist (listp) - List **listp; -{ - int i; - Node *p; - - if (*listp == (List *) NULL) - return; - - p = (*listp)->list; - - /* free each node in the list (except header) */ - while (p->next != p) - delnode (p->next); - - /* free any list-private data, without freeing the actual header */ - freenode_mem (p); - - /* free up the header nodes for hash lists (if any) */ - for (i = 0; i < HASHSIZE; i++) - { - if ((p = (*listp)->hasharray[i]) != (Node *) NULL) - { - /* put the nodes into the cache */ -#ifndef NOCACHE - p->type = NT_UNKNOWN; - p->next = nodecache; - nodecache = p; -#else - /* If NOCACHE is defined we turn off the cache. This can make - it easier to tools to determine where items were allocated - and freed, for tracking down memory leaks and the like. */ - free (p); -#endif - } - } - - /* put it on the cache */ -#ifndef NOCACHE - (*listp)->next = listcache; - listcache = *listp; -#else - free ((*listp)->list); - free (*listp); -#endif - *listp = (List *) NULL; -} - -/* - * get a new list node - */ -Node * -getnode () -{ - Node *p; - - if (nodecache != (Node *) NULL) - { - /* get one from the cache */ - p = nodecache; - nodecache = p->next; - } - else - { - /* make a new one */ - p = (Node *) xmalloc (sizeof (Node)); - } - - /* always make it clean */ - memset ((char *) p, 0, sizeof (Node)); - p->type = NT_UNKNOWN; - - return (p); -} - -/* - * remove a node from it's list (maybe hash list too) and free it - */ -void -delnode (p) - Node *p; -{ - if (p == (Node *) NULL) - return; - - /* take it out of the list */ - p->next->prev = p->prev; - p->prev->next = p->next; - - /* if it was hashed, remove it from there too */ - if (p->hashnext != (Node *) NULL) - { - p->hashnext->hashprev = p->hashprev; - p->hashprev->hashnext = p->hashnext; - } - - /* free up the storage */ - freenode (p); -} - -/* - * free up the storage associated with a node - */ -static void -freenode_mem (p) - Node *p; -{ - if (p->delproc != (void (*) ()) NULL) - p->delproc (p); /* call the specified delproc */ - else - { - if (p->data != NULL) /* otherwise free() it if necessary */ - free (p->data); - } - if (p->key != NULL) /* free the key if necessary */ - free (p->key); - - /* to be safe, re-initialize these */ - p->key = p->data = NULL; - p->delproc = (void (*) ()) NULL; -} - -/* - * free up the storage associated with a node and recycle it - */ -void -freenode (p) - Node *p; -{ - /* first free the memory */ - freenode_mem (p); - - /* then put it in the cache */ -#ifndef NOCACHE - p->type = NT_UNKNOWN; - p->next = nodecache; - nodecache = p; -#else - free (p); -#endif -} - -/* - * Link item P into list LIST before item MARKER. If P->KEY is non-NULL and - * that key is already in the hash table, return -1 without modifying any - * parameter. - * - * return 0 on success - */ -int -insert_before (list, marker, p) - List *list; - Node *marker; - Node *p; -{ - if (p->key != NULL) /* hash it too? */ - { - int hashval; - Node *q; - - hashval = hashp (p->key); - if (list->hasharray[hashval] == NULL) /* make a header for list? */ - { - q = getnode (); - q->type = HEADER; - list->hasharray[hashval] = q->hashnext = q->hashprev = q; - } - - /* put it into the hash list if it's not already there */ - for (q = list->hasharray[hashval]->hashnext; - q != list->hasharray[hashval]; q = q->hashnext) - { - if (strcmp (p->key, q->key) == 0) - return (-1); - } - q = list->hasharray[hashval]; - p->hashprev = q->hashprev; - p->hashnext = q; - p->hashprev->hashnext = p; - q->hashprev = p; - } - - p->next = marker; - p->prev = marker->prev; - marker->prev->next = p; - marker->prev = p; - - return (0); -} - -/* - * insert item p at end of list "list" (maybe hash it too) if hashing and it - * already exists, return -1 and don't actually put it in the list - * - * return 0 on success - */ -int -addnode (list, p) - List *list; - Node *p; -{ - return insert_before (list, list->list, p); -} - -/* - * Like addnode, but insert p at the front of `list'. This bogosity is - * necessary to preserve last-to-first output order for some RCS functions. - */ -int -addnode_at_front (list, p) - List *list; - Node *p; -{ - return insert_before (list, list->list->next, p); -} - -/* Look up an entry in hash list table and return a pointer to the - node. Return NULL if not found. Abort with a fatal error for - errors. */ -Node * -findnode (list, key) - List *list; - const char *key; -{ - Node *head, *p; - - /* This probably should be "assert (list != NULL)" (or if not we - should document the current behavior), but only if we check all - the callers to see if any are relying on this behavior. */ - if ((list == (List *) NULL)) - return ((Node *) NULL); - - assert (key != NULL); - - head = list->hasharray[hashp (key)]; - if (head == (Node *) NULL) - /* Not found. */ - return ((Node *) NULL); - - for (p = head->hashnext; p != head; p = p->hashnext) - if (strcmp (p->key, key) == 0) - return (p); - return ((Node *) NULL); -} - -/* - * Like findnode, but for a filename. - */ -Node * -findnode_fn (list, key) - List *list; - const char *key; -{ - Node *head, *p; - - /* This probably should be "assert (list != NULL)" (or if not we - should document the current behavior), but only if we check all - the callers to see if any are relying on this behavior. */ - if (list == (List *) NULL) - return ((Node *) NULL); - - assert (key != NULL); - - head = list->hasharray[hashp (key)]; - if (head == (Node *) NULL) - return ((Node *) NULL); - - for (p = head->hashnext; p != head; p = p->hashnext) - if (fncmp (p->key, key) == 0) - return (p); - return ((Node *) NULL); -} - -/* - * walk a list with a specific proc - */ -int -walklist (list, proc, closure) - List *list; - int (*proc) PROTO ((Node *, void *)); - void *closure; -{ - Node *head, *p; - int err = 0; - - if (list == NULL) - return (0); - - head = list->list; - for (p = head->next; p != head; p = p->next) - err += proc (p, closure); - return (err); -} - -int -list_isempty (list) - List *list; -{ - return list == NULL || list->list->next == list->list; -} - -static int (*client_comp) PROTO ((const Node *, const Node *)); -static int qsort_comp PROTO ((const void *, const void *)); - -static int -qsort_comp (elem1, elem2) - const void *elem1; - const void *elem2; -{ - Node **node1 = (Node **) elem1; - Node **node2 = (Node **) elem2; - return client_comp (*node1, *node2); -} - -/* - * sort the elements of a list (in place) - */ -void -sortlist (list, comp) - List *list; - int (*comp) PROTO ((const Node *, const Node *)); -{ - Node *head, *remain, *p, **array; - int i, n; - - if (list == NULL) - return; - - /* save the old first element of the list */ - head = list->list; - remain = head->next; - - /* count the number of nodes in the list */ - n = 0; - for (p = remain; p != head; p = p->next) - n++; - - /* allocate an array of nodes and populate it */ - array = (Node **) xmalloc (sizeof(Node *) * n); - i = 0; - for (p = remain; p != head; p = p->next) - array[i++] = p; - - /* sort the array of nodes */ - client_comp = comp; - qsort (array, n, sizeof(Node *), qsort_comp); - - /* rebuild the list from beginning to end */ - head->next = head->prev = head; - for (i = 0; i < n; i++) - { - p = array[i]; - p->next = head; - p->prev = head->prev; - p->prev->next = p; - head->prev = p; - } - - /* release the array of nodes */ - free (array); -} - -/* - * compare two files list node (for sort) - */ -int -fsortcmp (p, q) - const Node *p; - const Node *q; -{ - return (strcmp (p->key, q->key)); -} - -/* Debugging functions. Quite useful to call from within gdb. */ - -static char *nodetypestring PROTO ((Ntype)); - -static char * -nodetypestring (type) - Ntype type; -{ - switch (type) { - case NT_UNKNOWN: return("UNKNOWN"); - case HEADER: return("HEADER"); - case ENTRIES: return("ENTRIES"); - case FILES: return("FILES"); - case LIST: return("LIST"); - case RCSNODE: return("RCSNODE"); - case RCSVERS: return("RCSVERS"); - case DIRS: return("DIRS"); - case UPDATE: return("UPDATE"); - case LOCK: return("LOCK"); - case NDBMNODE: return("NDBMNODE"); - case FILEATTR: return("FILEATTR"); - case VARIABLE: return("VARIABLE"); - case RCSFIELD: return("RCSFIELD"); - case RCSCMPFLD: return("RCSCMPFLD"); - } - - return("<trash>"); -} - -static int printnode PROTO ((Node *, void *)); -static int -printnode (node, closure) - Node *node; - void *closure; -{ - if (node == NULL) - { - (void) printf("NULL node.\n"); - return(0); - } - - (void) printf("Node at %p: type = %s, key = %p = \"%s\", data = %p, next = %p, prev = %p\n", - (void *)node, nodetypestring(node->type), - (void *)node->key, node->key, node->data, - (void *)node->next, (void *)node->prev); - - return(0); -} - -/* This is global, not static, so that its name is unique and to avoid - compiler warnings about it not being used. But it is not used by CVS; - it exists so one can call it from a debugger. */ -void printlist PROTO ((List *)); - -void -printlist (list) - List *list; -{ - if (list == NULL) - { - (void) printf("NULL list.\n"); - return; - } - - (void) printf("List at %p: list = %p, HASHSIZE = %d, next = %p\n", - (void *)list, (void *)list->list, HASHSIZE, (void *)list->next); - - (void) walklist(list, printnode, NULL); - - return; -} diff --git a/contrib/cvs/src/hash.h b/contrib/cvs/src/hash.h deleted file mode 100644 index 77d095a..0000000 --- a/contrib/cvs/src/hash.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - */ - -/* - * The number of buckets for the hash table contained in each list. This - * should probably be prime. - */ -#define HASHSIZE 151 - -/* - * Types of nodes - */ -enum ntype -{ - NT_UNKNOWN, HEADER, ENTRIES, FILES, LIST, RCSNODE, - RCSVERS, DIRS, UPDATE, LOCK, NDBMNODE, FILEATTR, - VARIABLE, RCSFIELD, RCSCMPFLD -}; -typedef enum ntype Ntype; - -struct hashnode -{ - Ntype type; - struct hashnode *next; - struct hashnode *prev; - struct hashnode *hashnext; - struct hashnode *hashprev; - char *key; - void *data; - void (*delproc) (); -}; -typedef struct hashnode Node; - -struct hashlist -{ - Node *list; - Node *hasharray[HASHSIZE]; - struct hashlist *next; -}; -typedef struct hashlist List; - -List *getlist PROTO((void)); -Node *findnode PROTO((List * list, const char *key)); -Node *findnode_fn PROTO((List * list, const char *key)); -Node *getnode PROTO((void)); -int insert_before PROTO((List * list, Node * marker, Node * p)); -int addnode PROTO((List * list, Node * p)); -int addnode_at_front PROTO((List * list, Node * p)); -int walklist PROTO((List * list, int (*)(Node *n, void *closure), void *closure)); -int list_isempty PROTO ((List *list)); -void dellist PROTO((List ** listp)); -void delnode PROTO((Node * p)); -void freenode PROTO((Node * p)); -void sortlist PROTO((List * list, int (*)(const Node *, const Node *))); -int fsortcmp PROTO((const Node * p, const Node * q)); diff --git a/contrib/cvs/src/history.c b/contrib/cvs/src/history.c deleted file mode 100644 index 78fa0fe..0000000 --- a/contrib/cvs/src/history.c +++ /dev/null @@ -1,1666 +0,0 @@ -/* - * Copyright (C) 1994-2005 The Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* **************** History of Users and Module **************** - * - * LOGGING: Append record to "${CVSROOT}/CVSROOTADM/CVSROOTADM_HISTORY". - * - * On For each Tag, Add, Checkout, Commit, Update or Release command, - * one line of text is written to a History log. - * - * X date | user | CurDir | special | rev(s) | argument '\n' - * - * where: [The spaces in the example line above are not in the history file.] - * - * X is a single character showing the type of event: - * T "Tag" cmd. - * O "Checkout" cmd. - * E "Export" cmd. - * F "Release" cmd. - * W "Update" cmd - No User file, Remove from Entries file. - * U "Update" cmd - File was checked out over User file. - * P "Update" cmd - User file was patched. - * G "Update" cmd - File was merged successfully. - * C "Update" cmd - File was merged and shows overlaps. - * M "Commit" cmd - "Modified" file. - * A "Commit" cmd - "Added" file. - * R "Commit" cmd - "Removed" file. - * - * date is a fixed length 8-char hex representation of a Unix time_t. - * [Starting here, variable fields are delimited by '|' chars.] - * - * user is the username of the person who typed the command. - * - * CurDir The directory where the action occurred. This should be the - * absolute path of the directory which is at the same level as - * the "Repository" field (for W,U,P,G,C & M,A,R). - * - * Repository For record types [W,U,P,G,C,M,A,R] this field holds the - * repository read from the administrative data where the - * command was typed. - * T "A" --> New Tag, "D" --> Delete Tag - * Otherwise it is the Tag or Date to modify. - * O,F,E A "" (null field) - * - * rev(s) Revision number or tag. - * T The Tag to apply. - * O,E The Tag or Date, if specified, else "" (null field). - * F "" (null field) - * W The Tag or Date, if specified, else "" (null field). - * U,P The Revision checked out over the User file. - * G,C The Revision(s) involved in merge. - * M,A,R RCS Revision affected. - * - * argument The module (for [TOEF]) or file (for [WUPGCMAR]) affected. - * - * - *** Report categories: "User" and "Since" modifiers apply to all reports. - * [For "sort" ordering see the "sort_order" routine.] - * - * Extract list of record types - * - * -e, -x [TOEFWUPGCMAR] - * - * Extracted records are simply printed, No analysis is performed. - * All "field" modifiers apply. -e chooses all types. - * - * Checked 'O'ut modules - * - * -o, -w - * Checked out modules. 'F' and 'O' records are examined and if - * the last record for a repository/file is an 'O', a line is - * printed. "-w" forces the "working dir" to be used in the - * comparison instead of the repository. - * - * Committed (Modified) files - * - * -c, -l, -w - * All 'M'odified, 'A'dded and 'R'emoved records are examined. - * "Field" modifiers apply. -l forces a sort by file within user - * and shows only the last modifier. -w works as in Checkout. - * - * Warning: Be careful with what you infer from the output of - * "cvs hi -c -l". It means the last time *you* - * changed the file, not the list of files for which - * you were the last changer!!! - * - * Module history for named modules. - * -m module, -l - * - * This is special. If one or more modules are specified, the - * module names are remembered and the files making up the - * modules are remembered. Only records matching exactly those - * files and repositories are shown. Sorting by "module", then - * filename, is implied. If -l ("last modified") is specified, - * then "update" records (types WUPCG), tag and release records - * are ignored and the last (by date) "modified" record. - * - * TAG history - * - * -T All Tag records are displayed. - * - *** Modifiers. - * - * Since ... [All records contain a timestamp, so any report - * category can be limited by date.] - * - * -D date - The "date" is parsed into a Unix "time_t" and - * records with an earlier time stamp are ignored. - * -r rev/tag - A "rev" begins with a digit. A "tag" does not. If - * you use this option, every file is searched for the - * indicated rev/tag. - * -t tag - The "tag" is searched for in the history file and no - * record is displayed before the tag is found. An - * error is printed if the tag is never found. - * -b string - Records are printed only back to the last reference - * to the string in the "module", "file" or - * "repository" fields. - * - * Field Selections [Simple comparisons on existing fields. All field - * selections are repeatable.] - * - * -a - All users. - * -u user - If no user is given and '-a' is not given, only - * records for the user typing the command are shown. - * ==> If -a or -u is not specified, just use "self". - * - * -f filematch - Only records in which the "file" field contains the - * string "filematch" are considered. - * - * -p repository - Only records in which the "repository" string is a - * prefix of the "repos" field are considered. - * - * -n modulename - Only records which contain "modulename" in the - * "module" field are considered. - * - * - * EXAMPLES: ("cvs history", "cvs his" or "cvs hi") - * - *** Checked out files for username. (default self, e.g. "dgg") - * cvs hi [equivalent to: "cvs hi -o -u dgg"] - * cvs hi -u user [equivalent to: "cvs hi -o -u user"] - * cvs hi -o [equivalent to: "cvs hi -o -u dgg"] - * - *** Committed (modified) files from the beginning of the file. - * cvs hi -c [-u user] - * - *** Committed (modified) files since Midnight, January 1, 1990: - * cvs hi -c -D 'Jan 1 1990' [-u user] - * - *** Committed (modified) files since tag "TAG" was stored in the history file: - * cvs hi -c -t TAG [-u user] - * - *** Committed (modified) files since tag "TAG" was placed on the files: - * cvs hi -c -r TAG [-u user] - * - *** Who last committed file/repository X? - * cvs hi -c -l -[fp] X - * - *** Modified files since tag/date/file/repos? - * cvs hi -c {-r TAG | -D Date | -b string} - * - *** Tag history - * cvs hi -T - * - *** History of file/repository/module X. - * cvs hi -[fpn] X - * - *** History of user "user". - * cvs hi -e -u user - * - *** Dump (eXtract) specified record types - * cvs hi -x [TOEFWUPGCMAR] - * - * - * FUTURE: J[Join], I[Import] (Not currently implemented.) - * - */ - -#include "cvs.h" -#include "history.h" -#include "savecwd.h" - -static struct hrec -{ - char *type; /* Type of record (In history record) */ - char *user; /* Username (In history record) */ - char *dir; /* "Compressed" Working dir (In history record) */ - char *repos; /* (Tag is special.) Repository (In history record) */ - char *rev; /* Revision affected (In history record) */ - char *file; /* Filename (In history record) */ - char *end; /* Ptr into repository to copy at end of workdir */ - char *mod; /* The module within which the file is contained */ - time_t date; /* Calculated from date stored in record */ - long idx; /* Index of record, for "stable" sort. */ -} *hrec_head; -static long hrec_idx; - - -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)); -static int within PROTO((char *find, char *string)); -static void expand_modules PROTO((void)); -static void read_hrecs PROTO((char *fname)); -static void report_hrecs PROTO((void)); -static void save_file PROTO((char *dir, char *name, char *module)); -static void save_module PROTO((char *module)); -static void save_user PROTO((char *name)); - -#define USER_INCREMENT 2 -#define FILE_INCREMENT 128 -#define MODULE_INCREMENT 5 -#define HREC_INCREMENT 128 - -static short report_count; - -static short extract; -static short extract_all; -static short v_checkout; -static short modified; -static short tag_report; -static short module_report; -static short working; -static short last_entry; -static short all_users; - -static short user_sort; -static short repos_sort; -static short file_sort; -static short module_sort; - -static short tz_local; -static time_t tz_seconds_east_of_GMT; -static char *tz_name = "+0000"; - -char *logHistory; - -/* -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 - with since_date, these are a mutually exclusive set; one overrides the - others. */ -static char *since_rev; -static char *since_tag; -static char *backto; -/* -D option, or 0 if not specified. RCS format. */ -static char * since_date; - -static struct hrec *last_since_tag; -static struct hrec *last_backto; - -/* Record types to look for, malloc'd. Probably could be statically - allocated, but only if we wanted to check for duplicates more than - we do. */ -static char *rec_types; - -static size_t hrec_count; -static size_t hrec_max; - -static char **user_list; /* Ptr to array of ptrs to user names */ -static size_t user_max; /* Number of elements allocated */ -static size_t user_count; /* Number of elements used */ - -static struct file_list_str -{ - char *l_file; - char *l_module; -} *file_list; /* Ptr to array file name structs */ -static size_t file_max; /* Number of elements allocated */ -static size_t file_count; /* Number of elements used */ - -static char **mod_list; /* Ptr to array of ptrs to module names */ -static size_t mod_max; /* Number of elements allocated */ -static size_t mod_count; /* Number of elements used */ - -static char *histfile; /* Ptr to the history file name */ - -/* This is pretty unclear. First of all, separating "flags" vs. - "options" (I think the distinction is that "options" take arguments) - is nonstandard, and not something we do elsewhere in CVS. Second of - all, what does "reports" mean? I think it means that you can only - supply one of those options, but "reports" hardly has that meaning in - a self-explanatory way. */ -static const char *const history_usg[] = -{ - "Usage: %s %s [-report] [-flags] [-options args] [files...]\n\n", - " Reports:\n", - " -T Produce report on all TAGs\n", - " -c Committed (Modified) files\n", - " -o Checked out modules\n", - " -m <module> Look for specified module (repeatable)\n", - " -x [" ALL_HISTORY_REC_TYPES "] Extract by record type\n", - " -e Everything (same as -x, but all record types)\n", - " Flags:\n", - " -a All users (Default is self)\n", - " -l Last modified (committed or modified report)\n", - " -w Working directory must match\n", - " Options:\n", - " -D <date> Since date (Many formats)\n", - " -b <str> Back to record with str in module/file/repos field\n", - " -f <file> Specified file (same as command line) (repeatable)\n", - " -n <modulename> In module (repeatable)\n", - " -p <repos> In repository (repeatable)\n", - " -r <rev/tag> Since rev or tag (looks inside RCS files!)\n", - " -t <tag> Since tag record placed in history file (by anyone).\n", - " -u <user> For user name (repeatable)\n", - " -z <tz> Output for time zone <tz> (e.g. -z -0700)\n", - NULL}; - -/* Sort routine for qsort: - - If a user is selected at all, sort it first. User-within-file is useless. - - If a module was selected explicitly, sort next on module. - - Then sort by file. "File" is "repository/file" unless "working" is set, - then it is "workdir/file". (Revision order should always track date.) - - Always sort timestamp last. -*/ -static int -sort_order (l, r) - const PTR l; - const PTR r; -{ - int i; - const struct hrec *left = (const struct hrec *) l; - const struct hrec *right = (const struct hrec *) r; - - if (user_sort) /* If Sort by username, compare users */ - { - if ((i = strcmp (left->user, right->user)) != 0) - return (i); - } - if (module_sort) /* If sort by modules, compare module names */ - { - if (left->mod && right->mod) - if ((i = strcmp (left->mod, right->mod)) != 0) - return (i); - } - if (repos_sort) /* If sort by repository, compare them. */ - { - if ((i = strcmp (left->repos, right->repos)) != 0) - return (i); - } - if (file_sort) /* If sort by filename, compare files, NOT dirs. */ - { - if ((i = strcmp (left->file, right->file)) != 0) - return (i); - - if (working) - { - if ((i = strcmp (left->dir, right->dir)) != 0) - return (i); - - if ((i = strcmp (left->end, right->end)) != 0) - return (i); - } - } - - /* - * By default, sort by date, time - * XXX: This fails after 2030 when date slides into sign bit - */ - if ((i = ((long) (left->date) - (long) (right->date))) != 0) - return (i); - - /* For matching dates, keep the sort stable by using record index */ - return (left->idx - right->idx); -} - -int -history (argc, argv) - int argc; - char **argv; -{ - int i, c; - char *fname; - - if (argc == -1) - usage (history_usg); - - since_rev = xstrdup (""); - since_tag = xstrdup (""); - backto = xstrdup (""); - rec_types = xstrdup (""); - optind = 0; - while ((c = getopt (argc, argv, "+Tacelow?D:b:f:m:n:p:r:t:u:x:X:z:")) != -1) - { - switch (c) - { - case 'T': /* Tag list */ - report_count++; - tag_report++; - break; - case 'a': /* For all usernames */ - all_users++; - break; - case 'c': - report_count++; - modified = 1; - break; - case 'e': - report_count++; - extract_all++; - free (rec_types); - rec_types = xstrdup (ALL_HISTORY_REC_TYPES); - break; - case 'l': /* Find Last file record */ - last_entry = 1; - break; - case 'o': - report_count++; - v_checkout = 1; - break; - case 'w': /* Match Working Dir (CurDir) fields */ - working = 1; - break; - case 'X': /* Undocumented debugging flag */ -#ifdef DEBUG - histfile = optarg; -#endif - break; - - case 'D': /* Since specified date */ - if (*since_rev || *since_tag || *backto) - { - error (0, 0, "date overriding rev/tag/backto"); - *since_rev = *since_tag = *backto = '\0'; - } - since_date = Make_Date (optarg); - break; - case 'b': /* Since specified file/Repos */ - if (since_date || *since_rev || *since_tag) - { - error (0, 0, "backto overriding date/rev/tag"); - *since_rev = *since_tag = '\0'; - if (since_date != NULL) - free (since_date); - since_date = NULL; - } - free (backto); - backto = xstrdup (optarg); - break; - case 'f': /* For specified file */ - save_file (NULL, optarg, NULL); - break; - case 'm': /* Full module report */ - if (!module_report++) report_count++; - /* fall through */ - case 'n': /* Look for specified module */ - save_module (optarg); - break; - case 'p': /* For specified directory */ - save_file (optarg, NULL, NULL); - break; - case 'r': /* Since specified Tag/Rev */ - if (since_date || *since_tag || *backto) - { - error (0, 0, "rev overriding date/tag/backto"); - *since_tag = *backto = '\0'; - if (since_date != NULL) - free (since_date); - since_date = NULL; - } - free (since_rev); - since_rev = xstrdup (optarg); - break; - case 't': /* Since specified Tag/Rev */ - if (since_date || *since_rev || *backto) - { - error (0, 0, "tag overriding date/marker/file/repos"); - *since_rev = *backto = '\0'; - if (since_date != NULL) - free (since_date); - since_date = NULL; - } - free (since_tag); - since_tag = xstrdup (optarg); - break; - case 'u': /* For specified username */ - save_user (optarg); - break; - case 'x': - report_count++; - extract++; - { - char *cp; - - for (cp = optarg; *cp; cp++) - if (!strchr (ALL_HISTORY_REC_TYPES, *cp)) - error (1, 0, "%c is not a valid report type", *cp); - } - free (rec_types); - rec_types = xstrdup (optarg); - break; - case 'z': - tz_local = - (optarg[0] == 'l' || optarg[0] == 'L') - && (optarg[1] == 't' || optarg[1] == 'T') - && !optarg[2]; - if (tz_local) - tz_name = optarg; - else - { - /* - * Convert a known time with the given timezone to time_t. - * Use the epoch + 23 hours, so timezones east of GMT work. - */ - static char f[] = "1/1/1970 23:00 %s"; - char *buf = xmalloc (sizeof (f) - 2 + strlen (optarg)); - time_t t; - sprintf (buf, f, optarg); - t = get_date (buf, (struct timeb *) NULL); - free (buf); - if (t == (time_t) -1) - error (0, 0, "%s is not a known time zone", optarg); - else - { - /* - * Convert to seconds east of GMT, removing the - * 23-hour offset mentioned above. - */ - tz_seconds_east_of_GMT = (time_t)23 * 60 * 60 - t; - tz_name = optarg; - } - } - break; - case '?': - default: - usage (history_usg); - break; - } - } - argc -= optind; - argv += optind; - for (i = 0; i < argc; i++) - save_file (NULL, argv[i], 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: \"-Tcomxe\"."); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - struct file_list_str *f1; - char **mod; - - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (tag_report) - send_arg("-T"); - if (all_users) - send_arg("-a"); - if (modified) - send_arg("-c"); - if (last_entry) - send_arg("-l"); - if (v_checkout) - send_arg("-o"); - if (working) - send_arg("-w"); - if (histfile) - send_arg("-X"); - if (since_date) - client_senddate (since_date); - if (backto[0] != '\0') - option_with_arg ("-b", backto); - for (f1 = file_list; f1 < &file_list[file_count]; ++f1) - { - if (f1->l_file[0] == '*') - option_with_arg ("-p", f1->l_file + 1); - else - option_with_arg ("-f", f1->l_file); - } - if (module_report) - send_arg("-m"); - for (mod = mod_list; mod < &mod_list[mod_count]; ++mod) - option_with_arg ("-n", *mod); - if (*since_rev) - option_with_arg ("-r", since_rev); - if (*since_tag) - option_with_arg ("-t", since_tag); - for (mod = user_list; mod < &user_list[user_count]; ++mod) - option_with_arg ("-u", *mod); - if (extract_all) - send_arg("-e"); - if (extract) - option_with_arg ("-x", rec_types); - option_with_arg ("-z", tz_name); - - send_to_server ("history\012", 0); - return get_responses_and_close (); - } -#endif - - if (all_users) - save_user (""); - - if (mod_list) - expand_modules (); - - if (tag_report) - { - if (!strchr (rec_types, 'T')) - { - rec_types = xrealloc (rec_types, strlen (rec_types) + 5); - (void) strcat (rec_types, "T"); - } - } - else if (extract || extract_all) - { - if (user_list) - user_sort++; - } - else if (modified) - { - free (rec_types); - rec_types = xstrdup ("MAR"); - /* - * If the user has not specified a date oriented flag ("Since"), sort - * by Repository/file before date. Default is "just" date. - */ - if (last_entry - || (!since_date && !*since_rev && !*since_tag && !*backto)) - { - repos_sort++; - file_sort++; - /* - * If we are not looking for last_modified and the user specified - * one or more users to look at, sort by user before filename. - */ - if (!last_entry && user_list) - user_sort++; - } - } - else if (module_report) - { - free (rec_types); - rec_types = xstrdup (last_entry ? "OMAR" : ALL_HISTORY_REC_TYPES); - module_sort++; - repos_sort++; - file_sort++; - working = 0; /* User's workdir doesn't count here */ - } - else - /* Must be "checkout" or default */ - { - free (rec_types); - rec_types = xstrdup ("OF"); - /* See comments in "modified" above */ - if (!last_entry && user_list) - user_sort++; - if (last_entry - || (!since_date && !*since_rev && !*since_tag && !*backto)) - file_sort++; - } - - /* If no users were specified, use self (-a saves a universal ("") user) */ - if (!user_list) - save_user (getcaller ()); - - /* If we're looking back to a Tag value, must consider "Tag" records */ - if (*since_tag && !strchr (rec_types, 'T')) - { - rec_types = xrealloc (rec_types, strlen (rec_types) + 5); - (void) strcat (rec_types, "T"); - } - - if (histfile) - fname = xstrdup (histfile); - else - { - fname = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) - + sizeof (CVSROOTADM_HISTORY) + 10); - (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory, - CVSROOTADM, CVSROOTADM_HISTORY); - } - - read_hrecs (fname); - if(hrec_count>0) - { - qsort ((PTR) hrec_head, hrec_count, - sizeof (struct hrec), sort_order); - } - report_hrecs (); - free (fname); - if (since_date != NULL) - free (since_date); - free (since_rev); - free (since_tag); - free (backto); - free (rec_types); - - return (0); -} - -void -history_write (type, update_dir, revs, name, repository) - int type; - const char *update_dir; - const char *revs; - const char *name; - const char *repository; -{ - char *fname; - char *workdir; - char *username = getcaller (); - int fd; - char *line; - char *slash = "", *cp; - const char *cp2, *repos; - int i; - static char *tilde = ""; - static char *PrCurDir = NULL; - - if (logoff) /* History is turned off by noexec or - * readonlyfs. - */ - return; - if (strchr (logHistory, type) == NULL) - return; - fname = xmalloc (strlen (current_parsed_root->directory) - + sizeof (CVSROOTADM) - + sizeof (CVSROOTADM_HISTORY) + 3); - (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory, - CVSROOTADM, CVSROOTADM_HISTORY); - - /* turn off history logging if the history file does not exist */ - /* FIXME: This should check for write permissions instead. This way, - * O_CREATE could be added back into the call to open() below and - * there would be no race condition involved in log rotation. - * - * Note that the new method of turning off logging would be either via - * the CVSROOT/config file (probably the quicker method, but would need - * to be added, or at least checked for, too) or by creating a dummy - * history file with 0444 permissions. - */ - if (!isfile (fname)) - { - logoff = 1; - goto out; - } - - if (trace) - fprintf (stderr, "%s-> fopen(%s,a)\n", - CLIENT_SERVER_STR, fname); - if (noexec) - goto out; - - if (!history_lock (current_parsed_root->directory)) - /* history_lock() will already have printed an error on failure. */ - goto out; - - fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | OPEN_BINARY, 0666); - if (fd < 0) - { - if (! really_quiet) - { - error (0, errno, "warning: cannot write to history file %s", - fname); - } - goto out; - } - - repos = Short_Repository (repository); - - if (!PrCurDir) - { - char *pwdir; - - pwdir = get_homedir (); - PrCurDir = CurDir; - if (pwdir != NULL) - { - /* Assumes neither CurDir nor pwdir ends in '/' */ - i = strlen (pwdir); - if (!strncmp (CurDir, pwdir, i)) - { - PrCurDir += i; /* Point to '/' separator */ - tilde = "~"; - } - else - { - /* Try harder to find a "homedir" */ - struct saved_cwd cwd; - char *homedir; - - if (save_cwd (&cwd)) - error_exit (); - - if (CVS_CHDIR (pwdir) < 0 || (homedir = xgetwd ()) == NULL) - homedir = pwdir; - - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - - i = strlen (homedir); - if (!strncmp (CurDir, homedir, i)) - { - PrCurDir += i; /* Point to '/' separator */ - tilde = "~"; - } - - if (homedir != pwdir) - free (homedir); - } - } - } - - if (type == 'T') - { - repos = update_dir; - update_dir = ""; - } - else if (update_dir && *update_dir) - slash = "/"; - else - update_dir = ""; - - workdir = xmalloc (strlen (tilde) + strlen (PrCurDir) + strlen (slash) - + strlen (update_dir) + 10); - (void) sprintf (workdir, "%s%s%s%s", tilde, PrCurDir, slash, update_dir); - - /* - * "workdir" is the directory where the file "name" is. ("^~" == $HOME) - * "repos" is the Repository, relative to $CVSROOT where the RCS file is. - * - * "$workdir/$name" is the working file name. - * "$CVSROOT/$repos/$name,v" is the RCS file in the Repository. - * - * First, note that the history format was intended to save space, not - * to be human readable. - * - * The working file directory ("workdir") and the Repository ("repos") - * usually end with the same one or more directory elements. To avoid - * duplication (and save space), the "workdir" field ends with - * an integer offset into the "repos" field. This offset indicates the - * beginning of the "tail" of "repos", after which all characters are - * duplicates. - * - * In other words, if the "workdir" field has a '*' (a very stupid thing - * to put in a filename) in it, then every thing following the last '*' - * is a hex offset into "repos" of the first character from "repos" to - * append to "workdir" to finish the pathname. - * - * It might be easier to look at an example: - * - * M273b3463|dgg|~/work*9|usr/local/cvs/examples|1.2|loginfo - * - * Indicates that the workdir is really "~/work/cvs/examples", saving - * 10 characters, where "~/work*d" would save 6 characters and mean that - * the workdir is really "~/work/examples". It will mean more on - * directories like: usr/local/gnu/emacs/dist-19.17/lisp/term - * - * "workdir" is always an absolute pathname (~/xxx is an absolute path) - * "repos" is always a relative pathname. So we can assume that we will - * never run into the top of "workdir" -- there will always be a '/' or - * a '~' at the head of "workdir" that is not matched by anything in - * "repos". On the other hand, we *can* run off the top of "repos". - * - * Only "compress" if we save characters. - */ - - if (!repos) - repos = ""; - - cp = workdir + strlen (workdir) - 1; - cp2 = repos + strlen (repos) - 1; - for (i = 0; cp2 >= repos && cp > workdir && *cp == *cp2--; cp--) - i++; - - if (i > 2) - { - i = strlen (repos) - i; - (void) sprintf ((cp + 1), "*%x", i); - } - - if (!revs) - revs = ""; - line = xmalloc (strlen (username) + strlen (workdir) + strlen (repos) - + strlen (revs) + strlen (name) + 100); - sprintf (line, "%c%08lx|%s|%s|%s|%s|%s\n", - type, (long) time ((time_t *) NULL), - username, workdir, repos, revs, name); - - /* Lessen some race conditions on non-Posix-compliant hosts. */ - if (lseek (fd, (off_t) 0, SEEK_END) == -1) - error (1, errno, "cannot seek to end of history file: %s", fname); - - if (write (fd, line, strlen (line)) < 0) - error (1, errno, "cannot write to history file: %s", fname); - free (line); - if (close (fd) != 0) - error (1, errno, "cannot close history file: %s", fname); - free (workdir); - out: - clear_history_lock (); - free (fname); -} - -/* - * save_user() adds a user name to the user list to select. Zero-length - * username ("") matches any user. - */ -static void -save_user (name) - char *name; -{ - if (user_count == user_max) - { - user_max = xsum (user_max, USER_INCREMENT); - if (user_count == user_max - || size_overflow_p (xtimes (user_max, sizeof (char *)))) - { - error (0, 0, "save_user: too many users"); - return; - } - user_list = xrealloc (user_list, xtimes (user_max, sizeof (char *))); - } - user_list[user_count++] = xstrdup (name); -} - -/* - * save_file() adds file name and associated module to the file list to select. - * - * If "dir" is null, store a file name as is. - * If "name" is null, store a directory name with a '*' on the front. - * Else, store concatenated "dir/name". - * - * Later, in the "select" stage: - * - if it starts with '*', it is prefix-matched against the repository. - * - if it has a '/' in it, it is matched against the repository/file. - * - else it is matched against the file name. - */ -static void -save_file (dir, name, module) - char *dir; - char *name; - char *module; -{ - char *cp; - struct file_list_str *fl; - - if (file_count == file_max) - { - file_max = xsum (file_max, FILE_INCREMENT); - if (file_count == file_max - || size_overflow_p (xtimes (file_max, sizeof (*fl)))) - { - error (0, 0, "save_file: too many files"); - return; - } - file_list = xrealloc (file_list, xtimes (file_max, sizeof (*fl))); - } - fl = &file_list[file_count++]; - fl->l_file = cp = xmalloc (dir ? strlen (dir) : 0 - + name ? strlen (name) : 0 - + 2); - fl->l_module = module; - - if (dir && *dir) - { - if (name && *name) - { - (void) strcpy (cp, dir); - (void) strcat (cp, "/"); - (void) strcat (cp, name); - } - else - { - *cp++ = '*'; - (void) strcpy (cp, dir); - } - } - else - { - if (name && *name) - { - (void) strcpy (cp, name); - } - else - { - error (0, 0, "save_file: null dir and file name"); - } - } -} - -static void -save_module (module) - char *module; -{ - if (mod_count == mod_max) - { - mod_max = xsum (mod_max, MODULE_INCREMENT); - if (mod_count == mod_max - || size_overflow_p (xtimes (mod_max, sizeof (char *)))) - { - error (0, 0, "save_module: too many modules"); - return; - } - mod_list = xrealloc (mod_list, xtimes (mod_max, sizeof (char *))); - } - mod_list[mod_count++] = xstrdup (module); -} - -static void -expand_modules () -{ -} - -/* fill_hrec - * - * Take a ptr to 7-part history line, ending with a newline, for example: - * - * M273b3463|dgg|~/work*9|usr/local/cvs/examples|1.2|loginfo - * - * 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(*line)) line++; \ - hr->here = line; \ - while ((c = *line++) && c != '|') ; \ - if (!c) return; line[-1] = '\0'; \ - } while (0) - -static void -fill_hrec (line, hr) - char *line; - struct hrec *hr; -{ - char *cp; - int c; - - hr->type = hr->user = hr->dir = hr->repos = hr->rev = hr->file = - hr->end = hr->mod = NULL; - hr->date = -1; - hr->idx = ++hrec_idx; - - while (isspace ((unsigned char) *line)) - line++; - - hr->type = line++; - hr->date = strtoul (line, &cp, 16); - if (cp == line || *cp != '|') - return; - line = cp + 1; - NEXT_BAR (user); - NEXT_BAR (dir); - if ((cp = strrchr (hr->dir, '*')) != NULL) - { - *cp++ = '\0'; - hr->end = line + strtoul (cp, NULL, 16); - } - else - hr->end = line - 1; /* A handy pointer to '\0' */ - NEXT_BAR (repos); - NEXT_BAR (rev); - if (strchr ("FOET", *(hr->type))) - hr->mod = line; - - NEXT_BAR (file); -} - - -#ifndef STAT_BLOCKSIZE -#if HAVE_STRUCT_STAT_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 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; -{ - unsigned char *cpstart, *cpend, *cp, *nl; - char *hrline; - int i; - int fd; - struct stat st_buf; - - if ((fd = CVS_OPEN (fname, O_RDONLY | OPEN_BINARY)) < 0) - error (1, errno, "cannot open history file: %s", fname); - - if (fstat (fd, &st_buf) < 0) - error (1, errno, "can't stat history file"); - - if (!(st_buf.st_size)) - error (1, 0, "history file is empty"); - - cpstart = xmalloc (2 * STAT_BLOCKSIZE(st_buf)); - cpstart[0] = '\0'; - cp = cpend = cpstart; - - hrec_max = HREC_INCREMENT; - hrec_head = xmalloc (hrec_max * sizeof (struct hrec)); - hrec_idx = 0; - - for (;;) - { - for (nl = cp; nl < cpend && *nl != '\n'; nl++) - if (!isprint(*nl)) *nl = ' '; - - if (nl >= cpend) - { - if (nl - cp >= STAT_BLOCKSIZE(st_buf)) - { - error(1, 0, "history line %ld too long (> %lu)", hrec_idx + 1, - (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) - { - cpend = nl + i; - *cpend = '\0'; - continue; - } - if (i < 0) - error (1, errno, "error reading history file"); - if (nl == cp) break; - error (0, 0, "warning: no newline at end of history file"); - } - *nl = '\0'; - - if (hrec_count == hrec_max) - { - struct hrec *old_head = hrec_head; - - hrec_max = xsum (hrec_max, HREC_INCREMENT); - if (hrec_count == hrec_max - || size_overflow_p (xtimes (hrec_max, sizeof (struct hrec)))) - error (1, 0, "Too many history records in history file."); - - hrec_head = xrealloc (hrec_head, - xtimes (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); - } - - /* 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. */ - - 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 - * records since the *last* occurrence of "since_tag". So what we have - * to do is bump hrec_head forward and reduce hrec_count accordingly. - */ - if (last_since_tag) - { - hrec_count -= (last_since_tag - hrec_head); - hrec_head = last_since_tag; - } - - /* Much the same thing is necessary for the "backto" option. */ - if (last_backto) - { - hrec_count -= (last_backto - hrec_head); - hrec_head = last_backto; - } -} - -/* Utility program for determining whether "find" is inside "string" */ -static int -within (find, string) - char *find, *string; -{ - int c, len; - - if (!find || !string) - return (0); - - c = *find++; - len = strlen (find); - - while (*string) - { - if (!(string = strchr (string, c))) - return (0); - string++; - if (!strncmp (find, string, len)) - return (1); - } - return (0); -} - -/* The purpose of "select_hrec" is to apply the selection criteria based on - * the command arguments and defaults and return a flag indicating whether - * this record should be remembered for printing. - */ -static int -select_hrec (hr) - struct hrec *hr; -{ - char **cpp, *cp, *cp2; - struct file_list_str *fl; - int count; - - /* basic validity checking */ - if (!hr->type || !hr->user || !hr->dir || !hr->repos || !hr->rev || - !hr->file || !hr->end) - { - error (0, 0, "warning: history line %ld invalid", hr->idx); - return (0); - } - - /* "Since" checking: The argument parser guarantees that only one of the - * following four choices is set: - * - * 1. If "since_date" is set, it contains the date specified on the - * command line. hr->date fields earlier than "since_date" are ignored. - * 2. If "since_rev" is set, it contains either an RCS "dotted" revision - * number (which is of limited use) or a symbolic TAG. Each RCS file - * is examined and the date on the specified revision (or the revision - * corresponding to the TAG) in the RCS file (CVSROOT/repos/file) is - * compared against hr->date as in 1. above. - * 3. If "since_tag" is set, matching tag records are saved. The field - * "last_since_tag" is set to the last one of these. Since we don't - * know where the last one will be, all records are saved from the - * first occurrence of the TAG. Later, at the end of "select_hrec" - * records before the last occurrence of "since_tag" are skipped. - * 4. If "backto" is set, all records with a module name or file name - * matching "backto" are saved. In addition, all records with a - * repository field with a *prefix* matching "backto" are saved. - * The field "last_backto" is set to the last one of these. As in - * 3. above, "select_hrec" adjusts to include the last one later on. - */ - if (since_date) - { - char *ourdate = date_from_time_t (hr->date); - count = RCS_datecmp (ourdate, since_date); - free (ourdate); - if (count < 0) - return (0); - } - else if (*since_rev) - { - Vers_TS *vers; - time_t t; - struct file_info finfo; - - memset (&finfo, 0, sizeof finfo); - finfo.file = hr->file; - /* Not used, so don't worry about it. */ - finfo.update_dir = NULL; - finfo.fullname = finfo.file; - finfo.repository = hr->repos; - finfo.entries = NULL; - finfo.rcs = NULL; - - vers = Version_TS (&finfo, (char *) NULL, since_rev, (char *) NULL, - 1, 0); - if (vers->vn_rcs) - { - if ((t = RCS_getrevtime (vers->srcfile, vers->vn_rcs, (char *) 0, 0)) - != (time_t) 0) - { - if (hr->date < t) - { - freevers_ts (&vers); - return (0); - } - } - } - freevers_ts (&vers); - } - else if (*since_tag) - { - if (*(hr->type) == 'T') - { - /* - * A 'T'ag record, the "rev" field holds the tag to be set, - * while the "repos" field holds "D"elete, "A"dd or a rev. - */ - if (within (since_tag, hr->rev)) - { - last_since_tag = hr; - return (1); - } - else - return (0); - } - if (!last_since_tag) - return (0); - } - else if (*backto) - { - if (within (backto, hr->file) || within (backto, hr->mod) || - within (backto, hr->repos)) - last_backto = hr; - else - return (0); - } - - /* User checking: - * - * Run down "user_list", match username ("" matches anything) - * If "" is not there and actual username is not there, return failure. - */ - if (user_list && hr->user) - { - for (cpp = user_list, count = user_count; count; cpp++, count--) - { - if (!**cpp) - break; /* null user == accept */ - if (!strcmp (hr->user, *cpp)) /* found listed user */ - break; - } - if (!count) - return (0); /* Not this user */ - } - - /* Record type checking: - * - * 1. If Record type is not in rec_types field, skip it. - * 2. If mod_list is null, keep everything. Otherwise keep only modules - * on mod_list. - * 3. If neither a 'T', 'F' nor 'O' record, run through "file_list". If - * file_list is null, keep everything. Otherwise, keep only files on - * file_list, matched appropriately. - */ - if (!strchr (rec_types, *(hr->type))) - return (0); - if (!strchr ("TFOE", *(hr->type))) /* Don't bother with "file" if "TFOE" */ - { - if (file_list) /* If file_list is null, accept all */ - { - for (fl = file_list, count = file_count; count; fl++, count--) - { - /* 1. If file_list entry starts with '*', skip the '*' and - * compare it against the repository in the hrec. - * 2. If file_list entry has a '/' in it, compare it against - * the concatenation of the repository and file from hrec. - * 3. Else compare the file_list entry against the hrec file. - */ - char *cmpfile = NULL; - - if (*(cp = fl->l_file) == '*') - { - cp++; - /* if argument to -p is a prefix of repository */ - if (!strncmp (cp, hr->repos, strlen (cp))) - { - hr->mod = fl->l_module; - break; - } - } - else - { - if (strchr (cp, '/')) - { - cmpfile = xmalloc (strlen (hr->repos) - + strlen (hr->file) - + 10); - (void) sprintf (cmpfile, "%s/%s", - hr->repos, hr->file); - cp2 = cmpfile; - } - else - { - cp2 = hr->file; - } - - /* if requested file is found within {repos}/file fields */ - if (within (cp, cp2)) - { - hr->mod = fl->l_module; - if (cmpfile != NULL) - free (cmpfile); - break; - } - if (cmpfile != NULL) - free (cmpfile); - } - } - if (!count) - return (0); /* String specified and no match */ - } - } - if (mod_list) - { - for (cpp = mod_list, count = mod_count; count; cpp++, count--) - { - if (hr->mod && !strcmp (hr->mod, *cpp)) /* found module */ - break; - } - if (!count) - return (0); /* Module specified & this record is not one of them. */ - } - - return (1); /* Select this record unless rejected above. */ -} - -/* The "sort_order" routine (when handed to qsort) has arranged for the - * hrecs files to be in the right order for the report. - * - * Most of the "selections" are done in the select_hrec routine, but some - * selections are more easily done after the qsort by "accept_hrec". - */ -static void -report_hrecs () -{ - struct hrec *hr, *lr; - struct tm *tm; - int i, count, ty; - char *cp; - int user_len, file_len, rev_len, mod_len, repos_len; - - if (*since_tag && !last_since_tag) - { - (void) printf ("No tag found: %s\n", since_tag); - return; - } - else if (*backto && !last_backto) - { - (void) printf ("No module, file or repository with: %s\n", backto); - return; - } - else if (hrec_count < 1) - { - (void) printf ("No records selected.\n"); - return; - } - - user_len = file_len = rev_len = mod_len = repos_len = 0; - - /* Run through lists and find maximum field widths */ - hr = lr = hrec_head; - hr++; - for (count = hrec_count; count--; lr = hr, hr++) - { - char *repos; - - if (!count) - hr = NULL; - if (!accept_hrec (lr, hr)) - continue; - - ty = *(lr->type); - repos = xstrdup (lr->repos); - if ((cp = strrchr (repos, '/')) != NULL) - { - if (lr->mod && !strcmp (++cp, lr->mod)) - { - (void) strcpy (cp, "*"); - } - } - if ((i = strlen (lr->user)) > user_len) - user_len = i; - if ((i = strlen (lr->file)) > file_len) - file_len = i; - if (ty != 'T' && (i = strlen (repos)) > repos_len) - repos_len = i; - if (ty != 'T' && (i = strlen (lr->rev)) > rev_len) - rev_len = i; - if (lr->mod && (i = strlen (lr->mod)) > mod_len) - mod_len = i; - free (repos); - } - - /* Walk through hrec array setting "lr" (Last Record) to each element. - * "hr" points to the record following "lr" -- It is NULL in the last - * pass. - * - * There are two sections in the loop below: - * 1. Based on the report type (e.g. extract, checkout, tag, etc.), - * decide whether the record should be printed. - * 2. Based on the record type, format and print the data. - */ - for (lr = hrec_head, hr = (lr + 1); hrec_count--; lr = hr, hr++) - { - char *workdir; - char *repos; - - if (!hrec_count) - hr = NULL; - if (!accept_hrec (lr, hr)) - continue; - - ty = *(lr->type); - if (!tz_local) - { - time_t t = lr->date + tz_seconds_east_of_GMT; - tm = gmtime (&t); - } - else - tm = localtime (&(lr->date)); - - (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); - if ((cp = strrchr (workdir, '/')) != NULL) - { - if (lr->mod && !strcmp (++cp, lr->mod)) - { - (void) strcpy (cp, "*"); - } - } - repos = xmalloc (strlen (lr->repos) + 10); - (void) strcpy (repos, lr->repos); - if ((cp = strrchr (repos, '/')) != NULL) - { - if (lr->mod && !strcmp (++cp, lr->mod)) - { - (void) strcpy (cp, "*"); - } - } - - switch (ty) - { - case 'T': - /* 'T'ag records: repository is a "tag type", rev is the tag */ - (void) printf (" %-*s [%s:%s]", mod_len, lr->mod, lr->rev, - repos); - if (working) - (void) printf (" {%s}", workdir); - break; - case 'F': - case 'E': - case 'O': - if (lr->rev && *(lr->rev)) - (void) printf (" [%s]", lr->rev); - (void) printf (" %-*s =%s%-*s %s", repos_len, repos, lr->mod, - mod_len + 1 - (int) strlen (lr->mod), - "=", workdir); - break; - case 'W': - case 'U': - case 'P': - case 'C': - case 'G': - case 'M': - case 'A': - case 'R': - (void) printf (" %-*s %-*s %-*s =%s= %s", rev_len, lr->rev, - file_len, lr->file, repos_len, repos, - lr->mod ? lr->mod : "", workdir); - break; - default: - (void) printf ("Hey! What is this junk? RecType[0x%2.2x]", ty); - break; - } - (void) putchar ('\n'); - free (workdir); - free (repos); - } -} - -static int -accept_hrec (lr, hr) - struct hrec *hr, *lr; -{ - int ty; - - ty = *(lr->type); - - if (last_since_tag && ty == 'T') - return (1); - - if (v_checkout) - { - if (ty != 'O') - return (0); /* Only interested in 'O' records */ - - /* We want to identify all the states that cause the next record - * ("hr") to be different from the current one ("lr") and only - * print a line at the allowed boundaries. - */ - - if (!hr || /* The last record */ - strcmp (hr->user, lr->user) || /* User has changed */ - strcmp (hr->mod, lr->mod) ||/* Module has changed */ - (working && /* If must match "workdir" */ - (strcmp (hr->dir, lr->dir) || /* and the 1st parts or */ - strcmp (hr->end, lr->end)))) /* the 2nd parts differ */ - - return (1); - } - else if (modified) - { - if (!last_entry || /* Don't want only last rec */ - !hr || /* Last entry is a "last entry" */ - strcmp (hr->repos, lr->repos) || /* Repository has changed */ - strcmp (hr->file, lr->file))/* File has changed */ - return (1); - - if (working) - { /* If must match "workdir" */ - if (strcmp (hr->dir, lr->dir) || /* and the 1st parts or */ - strcmp (hr->end, lr->end)) /* the 2nd parts differ */ - return (1); - } - } - else if (module_report) - { - if (!last_entry || /* Don't want only last rec */ - !hr || /* Last entry is a "last entry" */ - strcmp (hr->mod, lr->mod) ||/* Module has changed */ - strcmp (hr->repos, lr->repos) || /* Repository has changed */ - strcmp (hr->file, lr->file))/* File has changed */ - return (1); - } - else - { - /* "extract" and "tag_report" always print selected records. */ - return (1); - } - - return (0); -} diff --git a/contrib/cvs/src/history.h b/contrib/cvs/src/history.h deleted file mode 100644 index dadc421..0000000 --- a/contrib/cvs/src/history.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2003-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 2003-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * You may distribute under the terms of the GNU General Public License - * as specified in the README file that comes with the CVS source - * distribution. - * - * This is the header file for definitions and functions shared by history.c - * with other portions of CVS. - */ - -#define ALL_HISTORY_REC_TYPES "TOEFWUPCGMAR" diff --git a/contrib/cvs/src/ignore.c b/contrib/cvs/src/ignore.c deleted file mode 100644 index 65b2260..0000000 --- a/contrib/cvs/src/ignore.c +++ /dev/null @@ -1,503 +0,0 @@ -/* This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -/* - * .cvsignore file support contributed by David G. Grubbs <dgg@odi.com> - */ - -#include "cvs.h" -#include "getline.h" - -/* - * Ignore file section. - * - * "!" may be included any time to reset the list (i.e. ignore nothing); - * "*" may be specified to ignore everything. It stays as the first - * element forever, unless a "!" clears it out. - */ - -static char **ign_list; /* List of files to ignore in update - * and import */ -static char **s_ign_list = NULL; -static int ign_count; /* Number of active entries */ -static int s_ign_count = 0; -static int ign_size; /* This many slots available (plus - * one for a NULL) */ -static int ign_hold = -1; /* Index where first "temporary" item - * is held */ - -const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state\ - .nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj\ - *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$"; - -#define IGN_GROW 16 /* grow the list by 16 elements at a - * time */ - -/* Nonzero if we have encountered an -I ! directive, which means one should - no longer ask the server about what is in CVSROOTADM_IGNORE. */ -int ign_inhibit_server; - - - -/* - * To the "ignore list", add the hard-coded default ignored wildcards above, - * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in - * ~/.cvsignore and the wildcards found in the CVSIGNORE environment - * variable. - */ -void -ign_setup () -{ - char *home_dir; - char *tmp; - - ign_inhibit_server = 0; - - /* Start with default list and special case */ - tmp = xstrdup (ign_default); - ign_add (tmp, 0); - free (tmp); - - /* The client handles another way, by (after it does its own ignore file - processing, and only if !ign_inhibit_server), letting the server - know about the files and letting it decide whether to ignore - them based on CVSROOOTADM_IGNORE. */ - if (!current_parsed_root->isremote) - { - char *file = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) - + sizeof (CVSROOTADM_IGNORE) + 10); - /* Then add entries found in repository, if it exists */ - (void) sprintf (file, "%s/%s/%s", current_parsed_root->directory, - CVSROOTADM, CVSROOTADM_IGNORE); - ign_add_file (file, 0); - free (file); - } - - /* Then add entries found in home dir, (if user has one) and file exists */ - home_dir = get_homedir (); - /* If we can't find a home directory, ignore ~/.cvsignore. This may - make tracking down problems a bit of a pain, but on the other - hand it might be obnoxious to complain when CVS will function - just fine without .cvsignore (and many users won't even know what - .cvsignore is). */ - if (home_dir) - { - char *file = strcat_filename_onto_homedir (home_dir, CVSDOTIGNORE); - ign_add_file (file, 0); - free (file); - } - - /* Then add entries found in CVSIGNORE environment variable. */ - ign_add (getenv (IGNORE_ENV), 0); - - /* Later, add ignore entries found in -I arguments */ -} - - - -/* - * Open a file and read lines, feeding each line to a line parser. Arrange - * for keeping a temporary list of wildcards at the end, if the "hold" - * argument is set. - */ -void -ign_add_file (file, hold) - char *file; - int hold; -{ - FILE *fp; - char *line = NULL; - size_t line_allocated = 0; - - /* restore the saved list (if any) */ - if (s_ign_list != NULL) - { - int i; - - for (i = 0; i < s_ign_count; i++) - ign_list[i] = s_ign_list[i]; - ign_count = s_ign_count; - ign_list[ign_count] = NULL; - - s_ign_count = 0; - free (s_ign_list); - s_ign_list = NULL; - } - - /* is this a temporary ignore file? */ - if (hold) - { - /* re-set if we had already done a temporary file */ - if (ign_hold >= 0) - { - int i; - - for (i = ign_hold; i < ign_count; i++) - free (ign_list[i]); - ign_count = ign_hold; - ign_list[ign_count] = NULL; - } - else - { - ign_hold = ign_count; - } - } - - /* load the file */ - fp = CVS_FOPEN (file, "r"); - if (fp == NULL) - { - if (! existence_error (errno)) - error (0, errno, "cannot open %s", file); - return; - } - while (getline (&line, &line_allocated, fp) >= 0) - ign_add (line, hold); - if (ferror (fp)) - error (0, errno, "cannot read %s", file); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", file); - free (line); -} - - - -/* Parse a line of space-separated wildcards and add them to the list. */ -void -ign_add (ign, hold) - char *ign; - int hold; -{ - if (!ign || !*ign) - return; - - for (; *ign; ign++) - { - char *mark; - char save; - - /* ignore whitespace before the token */ - if (isspace ((unsigned char) *ign)) - continue; - - /* If we have used up all the space, add some more. Do this before - processing `!', since an "empty" list still contains the `CVS' - entry. */ - if (ign_count >= ign_size) - { - ign_size += IGN_GROW; - ign_list = (char **) xrealloc ((char *) ign_list, - (ign_size + 1) * sizeof (char *)); - } - - /* - * if we find a single character !, we must re-set the ignore list - * (saving it if necessary). We also catch * as a special case in a - * global ignore file as an optimization - */ - if ((!*(ign+1) || isspace ((unsigned char) *(ign+1))) - && (*ign == '!' || *ign == '*')) - { - if (!hold) - { - /* permanently reset the ignore list */ - int i; - - for (i = 0; i < ign_count; i++) - free (ign_list[i]); - ign_count = 1; - /* Always ignore the "CVS" directory. */ - ign_list[0] = xstrdup("CVS"); - ign_list[1] = NULL; - - /* if we are doing a '!', continue; otherwise add the '*' */ - if (*ign == '!') - { - ign_inhibit_server = 1; - continue; - } - } - else if (*ign == '!') - { - /* temporarily reset the ignore list */ - int i; - - if (ign_hold >= 0) - { - for (i = ign_hold; i < ign_count; i++) - free (ign_list[i]); - ign_hold = -1; - } - if (s_ign_list) - { - /* Don't save the ignore list twice - if there are two - * bangs in a local .cvsignore file then we don't want to - * save the new list the first bang created. - * - * We still need to free the "new" ignore list. - */ - for (i = 0; i < ign_count; i++) - free (ign_list[i]); - } - else - { - /* Save the ignore list for later. */ - s_ign_list = xmalloc (ign_count * sizeof (char *)); - for (i = 0; i < ign_count; i++) - s_ign_list[i] = ign_list[i]; - s_ign_count = ign_count; - } - ign_count = 1; - /* Always ignore the "CVS" directory. */ - ign_list[0] = xstrdup ("CVS"); - ign_list[1] = NULL; - continue; - } - } - - /* find the end of this token */ - for (mark = ign; *mark && !isspace ((unsigned char) *mark); mark++) - /* do nothing */ ; - - save = *mark; - *mark = '\0'; - - ign_list[ign_count++] = xstrdup (ign); - ign_list[ign_count] = NULL; - - *mark = save; - if (save) - ign = mark; - else - ign = mark - 1; - } -} - - - -/* Return true if the given filename should be ignored by update or import, - * else return false. - */ -int -ign_name (name) - char *name; -{ - char **cpp = ign_list; - - if (cpp == NULL) - return 0; - - while (*cpp) - if (CVS_FNMATCH (*cpp++, name, 0) == 0) - return 1; - - return 0; -} - - - -/* FIXME: This list of dirs to ignore stuff seems not to be used. - Really? send_dirent_proc and update_dirent_proc both call - ignore_directory and do_module calls ign_dir_add. No doubt could - use some documentation/testsuite work. */ - -static char **dir_ign_list = NULL; -static int dir_ign_max = 0; -static int dir_ign_current = 0; - -/* Add a directory to list of dirs to ignore. */ -void -ign_dir_add (name) - char *name; -{ - /* Make sure we've got the space for the entry. */ - if (dir_ign_current <= dir_ign_max) - { - dir_ign_max += IGN_GROW; - dir_ign_list = - (char **) xrealloc (dir_ign_list, - (dir_ign_max + 1) * sizeof (char *)); - } - - dir_ign_list[dir_ign_current++] = xstrdup (name); -} - - -/* Return nonzero if NAME is part of the list of directories to ignore. */ - -int -ignore_directory (name) - const char *name; -{ - int i; - - if (!dir_ign_list) - return 0; - - i = dir_ign_current; - while (i--) - { - if (strncmp (name, dir_ign_list[i], strlen (dir_ign_list[i])+1) == 0) - return 1; - } - - return 0; -} - - - -/* - * Process the current directory, looking for files not in ILIST and - * not on the global ignore list for this directory. If we find one, - * call PROC passing it the name of the file and the update dir. - * ENTRIES is the entries list, which is used to identify known - * directories. ENTRIES may be NULL, in which case we assume that any - * directory with a CVS administration directory is known. - */ -void -ignore_files (ilist, entries, update_dir, proc) - List *ilist; - List *entries; - const char *update_dir; - Ignore_proc proc; -{ - int subdirs; - DIR *dirp; - struct dirent *dp; - struct stat sb; - char *file; - const char *xdir; - List *files; - Node *p; - - /* Set SUBDIRS if we have subdirectory information in ENTRIES. */ - if (entries == NULL) - subdirs = 0; - else - { - struct stickydirtag *sdtp = entries->list->data; - - subdirs = sdtp == NULL || sdtp->subdirs; - } - - /* we get called with update_dir set to "." sometimes... strip it */ - if (strcmp (update_dir, ".") == 0) - xdir = ""; - else - xdir = update_dir; - - dirp = CVS_OPENDIR ("."); - if (dirp == NULL) - { - error (0, errno, "cannot open current directory"); - return; - } - - ign_add_file (CVSDOTIGNORE, 1); - wrap_add_file (CVSDOTWRAPPER, 1); - - /* Make a list for the files. */ - files = getlist (); - - while (errno = 0, (dp = CVS_READDIR (dirp)) != NULL) - { - file = dp->d_name; - if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0) - continue; - if (findnode_fn (ilist, file) != NULL) - continue; - if (subdirs) - { - Node *node; - - node = findnode_fn (entries, file); - if (node != NULL - && ((Entnode *) node->data)->type == ENT_SUBDIR) - { - char *p; - int dir; - - /* For consistency with past behaviour, we only ignore - this directory if there is a CVS subdirectory. - This will normally be the case, but the user may - have messed up the working directory somehow. */ - p = xmalloc (strlen (file) + sizeof CVSADM + 10); - sprintf (p, "%s/%s", file, CVSADM); - dir = isdir (p); - free (p); - if (dir) - continue; - } - } - - /* We could be ignoring FIFOs and other files which are neither - regular files nor directories here. */ - if (ign_name (file)) - continue; - - if ( -#ifdef DT_DIR - dp->d_type != DT_UNKNOWN || -#endif - CVS_LSTAT (file, &sb) != -1) - { - - if ( -#ifdef DT_DIR - dp->d_type == DT_DIR - || (dp->d_type == DT_UNKNOWN && S_ISDIR (sb.st_mode)) -#else - S_ISDIR (sb.st_mode) -#endif - ) - { - if (! subdirs) - { - char *temp; - - temp = xmalloc (strlen (file) + sizeof (CVSADM) + 10); - (void) sprintf (temp, "%s/%s", file, CVSADM); - if (isdir (temp)) - { - free (temp); - continue; - } - free (temp); - } - } -#ifdef S_ISLNK - else if ( -#ifdef DT_DIR - dp->d_type == DT_LNK - || (dp->d_type == DT_UNKNOWN && S_ISLNK(sb.st_mode)) -#else - S_ISLNK (sb.st_mode) -#endif - ) - { - continue; - } -#endif - } - - p = getnode (); - p->type = FILES; - p->key = xstrdup (file); - (void) addnode (files, p); - } - if (errno != 0) - error (0, errno, "error reading current directory"); - (void) CVS_CLOSEDIR (dirp); - - sortlist (files, fsortcmp); - for (p = files->list->next; p != files->list; p = p->next) - (*proc) (p->key, xdir); - dellist (&files); -} diff --git a/contrib/cvs/src/import.c b/contrib/cvs/src/import.c deleted file mode 100644 index bc918e0..0000000 --- a/contrib/cvs/src/import.c +++ /dev/null @@ -1,1653 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * "import" checks in the vendor release located in the current directory into - * the CVS source repository. The CVS vendor branch support is utilized. - * - * At least three arguments are expected to follow the options: - * repository Where the source belongs relative to the CVSROOT - * VendorTag Vendor's major tag - * VendorReleTag Tag for this particular release - * - * Additional arguments specify more Vendor Release Tags. - */ - -#include "cvs.h" -#include "savecwd.h" -#include <assert.h> - -static char *get_comment PROTO((const char *user)); -static int add_rev PROTO((char *message, RCSNode *rcs, char *vfile, - char *vers)); -static int add_tags PROTO((RCSNode *rcs, char *vfile, char *vtag, int targc, - char *targv[])); -static int import_descend PROTO((char *message, char *vtag, int targc, char *targv[])); -static int import_descend_dir PROTO((char *message, char *dir, char *vtag, - int targc, char *targv[])); -static int process_import_file PROTO((char *message, char *vfile, char *vtag, - int targc, char *targv[])); -static int update_rcs_file PROTO((char *message, char *vfile, char *vtag, int targc, - char *targv[], int inattic)); -static void add_log PROTO((int ch, char *fname)); - -static int repos_len; -static char *vhead; -static char *vbranch; -static FILE *logfp; -static char *repository; -static int conflicts; -static int use_file_modtime; -static char *keyword_opt = NULL; - -static const char *const import_usage[] = -{ - "Usage: %s %s [-d] [-k subst] [-I ign] [-m msg] [-b branch]\n", - " [-W spec] repository vendor-tag release-tags...\n", - "\t-d\tUse the file's modification time as the time of import.\n", - "\t-k sub\tSet default RCS keyword substitution mode.\n", - "\t-I ign\tMore files to ignore (! to reset).\n", - "\t-b bra\tVendor branch id.\n", - "\t-m msg\tLog message.\n", - "\t-W spec\tWrappers specification line.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -int -import (argc, argv) - int argc; - char **argv; -{ - char *message = NULL; - char *tmpfile; - char *cp; - int i, c, msglen, err; - List *ulist; - Node *p; - struct logfile_info *li; - - if (argc == -1) - usage (import_usage); - - ign_setup (); - wrap_setup (); - - vbranch = xstrdup (CVSBRANCH); - optind = 0; - while ((c = getopt (argc, argv, "+Qqdb:m:I:k:W:")) != -1) - { - switch (c) - { - case 'Q': - case 'q': - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) - error (1, 0, - "-q or -Q must be specified before \"%s\"", - cvs_cmd_name); - break; - case 'd': - if (server_active) - { - /* CVS 1.10 and older clients will send this, but it - doesn't do any good. So tell the user we can't - cope, rather than silently losing. */ - error (0, 0, - "warning: not setting the time of import from the file"); - error (0, 0, "due to client limitations"); - } - use_file_modtime = 1; - break; - case 'b': - free (vbranch); - vbranch = xstrdup (optarg); - break; - case 'm': -#ifdef FORCE_USE_EDITOR - use_editor = 1; -#else - use_editor = 0; -#endif - if (message) free (message); - message = xstrdup(optarg); - break; - case 'I': - ign_add (optarg, 0); - break; - case 'k': - /* RCS_check_kflag returns strings of the form -kxx. We - only use it for validation, so we can free the value - as soon as it is returned. */ - free (RCS_check_kflag (optarg)); - keyword_opt = optarg; - break; - case 'W': - wrap_add (optarg, 0); - break; - case '?': - default: - usage (import_usage); - break; - } - } - argc -= optind; - argv += optind; - if (argc < 3) - usage (import_usage); - - /* This is for handling the Checkin-time request. It might seem a - bit odd to enable the use_file_modtime code even in the case - where Checkin-time was not sent for a particular file. The - effect is that we use the time of upload, rather than the time - when we call RCS_checkin. Since those times are both during - CVS's run, that seems OK, and it is easier to implement than - putting the "was Checkin-time sent" flag in CVS/Entries or some - such place. */ - - if (server_active) - use_file_modtime = 1; - - /* Don't allow "CVS" as any directory in module path. - * - * Could abstract this to valid_module_path, but I don't think we'll need - * to call it from anywhere else. - */ - /* for each "CVS" in path... */ - cp = argv[0]; - while ((cp = strstr(cp, "CVS")) != NULL) - { - if ( /* /^CVS/ OR m#/CVS#... */ - (cp == argv[0] || ISDIRSEP(*(cp-1))) - /* ...AND /CVS$/ OR m#CVS/# */ - && (*(cp+3) == '\0' || ISDIRSEP(*(cp+3))) - ) - { - error (0, 0, - "The word `CVS' is reserved by CVS and may not be used"); - error (1, 0, "as a directory in a path or as a file name."); - } - cp += 3; - } - - for (i = 1; i < argc; i++) /* check the tags for validity */ - { - int j; - - RCS_check_tag (argv[i]); - for (j = 1; j < i; j++) - if (strcmp (argv[j], argv[i]) == 0) - error (1, 0, "tag `%s' was specified more than once", argv[i]); - } - - /* XXX - this should be a module, not just a pathname */ - if (!isabsolute (argv[0]) && pathname_levels (argv[0]) == 0) - { - if (current_parsed_root == NULL) - { - error (0, 0, "missing CVSROOT environment variable\n"); - error (1, 0, "Set it or specify the '-d' option to %s.", - program_name); - } - repository = xmalloc (strlen (current_parsed_root->directory) - + strlen (argv[0]) - + 2); - (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); - repos_len = strlen (current_parsed_root->directory); - } - else - { - /* It is somewhere between a security hole and "unexpected" to - let the client start mucking around outside the cvsroot - (wouldn't get the right CVSROOT configuration, &c). */ - error (1, 0, "directory %s not relative within the repository", - argv[0]); - } - - /* - * Consistency checks on the specified vendor branch. It must be - * composed of only numbers and dots ('.'). Also, for now we only - * support branching to a single level, so the specified vendor branch - * must only have two dots in it (like "1.1.1"). - */ - { - regex_t pat; - int ret = regcomp (&pat, "^[1-9][0-9]*\\.[1-9][0-9]*\\.[1-9][0-9]*$", - REG_EXTENDED); - assert (!ret); - if (regexec (&pat, vbranch, 0, NULL, 0)) - { - error (1, 0, -"Only numeric branch specifications with two dots are\n" -"supported by import, not `%s'. For example: `1.1.1'.", - vbranch); - } - regfree (&pat); - } - - /* Set vhead to the branch's parent. */ - vhead = xstrdup (vbranch); - cp = strrchr (vhead, '.'); - *cp = '\0'; - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - /* For rationale behind calling start_server before do_editor, see - commit.c */ - start_server (); - } -#endif - - if (!server_active && use_editor) - { - do_editor ((char *) NULL, &message, - current_parsed_root->isremote ? (char *) NULL : repository, - (List *) NULL); - } - do_verify (&message, repository); - msglen = message == NULL ? 0 : strlen (message); - if (msglen == 0 || message[msglen - 1] != '\n') - { - char *nm = xmalloc (msglen + 2); - *nm = '\0'; - if (message != NULL) - { - (void) strcpy (nm, message); - free (message); - } - (void) strcat (nm + msglen, "\n"); - message = nm; - } - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - int err; - - if (vbranch[0] != '\0') - option_with_arg ("-b", vbranch); - option_with_arg ("-m", message ? message : ""); - if (keyword_opt != NULL) - option_with_arg ("-k", keyword_opt); - /* The only ignore processing which takes place on the server side - is the CVSROOT/cvsignore file. But if the user specified -I !, - the documented behavior is to not process said file. */ - if (ign_inhibit_server) - { - send_arg ("-I"); - send_arg ("!"); - } - wrap_send (); - - { - int i; - for (i = 0; i < argc; ++i) - send_arg (argv[i]); - } - - logfp = stdin; - 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 ( NULL )) - { - error (1, 0, "attempt to import the repository"); - } - - /* - * Make all newly created directories writable. Should really use a more - * sophisticated security mechanism here. - */ - (void) umask (cvsumask); - make_directories (repository); - - /* Create the logfile that will be logged upon completion */ - if ((logfp = cvs_temp_file (&tmpfile)) == NULL) - error (1, errno, "cannot create temporary file `%s'", - tmpfile ? tmpfile : "(null)"); - /* On systems where we can unlink an open file, do so, so it will go - away no matter how we exit. FIXME-maybe: Should be checking for - errors but I'm not sure which error(s) we get if we are on a system - where one can't unlink open files. */ - (void) CVS_UNLINK (tmpfile); - (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]); - (void) fprintf (logfp, "Release Tags:\t"); - for (i = 2; i < argc; i++) - (void) fprintf (logfp, "%s\n\t\t", argv[i]); - (void) fprintf (logfp, "\n"); - - /* Just Do It. */ - err = import_descend (message, argv[1], argc - 2, argv + 2); - if (conflicts) - { - if (!really_quiet) - { - char buf[20]; - - cvs_output_tagged ("+importmergecmd", NULL); - cvs_output_tagged ("newline", NULL); - sprintf (buf, "%d", conflicts); - cvs_output_tagged ("conflicts", buf); - cvs_output_tagged ("text", " conflicts created by this import."); - cvs_output_tagged ("newline", NULL); - cvs_output_tagged ("text", - "Use the following command to help the merge:"); - cvs_output_tagged ("newline", NULL); - cvs_output_tagged ("newline", NULL); - cvs_output_tagged ("text", "\t"); - cvs_output_tagged ("text", program_name); - if (CVSroot_cmdline != NULL) - { - cvs_output_tagged ("text", " -d "); - cvs_output_tagged ("text", CVSroot_cmdline); - } - cvs_output_tagged ("text", " checkout -j"); - cvs_output_tagged ("mergetag1", "<prev_rel_tag>"); - cvs_output_tagged ("text", " -j"); - cvs_output_tagged ("mergetag2", argv[2]); - cvs_output_tagged ("text", " "); - cvs_output_tagged ("repository", argv[0]); - cvs_output_tagged ("newline", NULL); - cvs_output_tagged ("newline", NULL); - cvs_output_tagged ("-importmergecmd", NULL); - } - - /* FIXME: I'm not sure whether we need to put this information - into the loginfo. If we do, then note that it does not - report any required -d option. There is no particularly - clean way to tell the server about the -d option used by - the client. */ - (void) fprintf (logfp, "\n%d conflicts created by this import.\n", - conflicts); - (void) fprintf (logfp, - "Use the following command to help the merge:\n\n"); - (void) fprintf (logfp, "\t%s checkout ", program_name); - (void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n", - argv[1], argv[1], argv[0]); - } - else - { - if (!really_quiet) - cvs_output ("\nNo conflicts created by this import\n\n", 0); - (void) fprintf (logfp, "\nNo conflicts created by this import\n\n"); - } - - /* - * Write out the logfile and clean up. - */ - ulist = getlist (); - p = getnode (); - p->type = UPDATE; - p->delproc = update_delproc; - p->key = xstrdup ("- Imported sources"); - li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info)); - li->type = T_TITLE; - li->tag = xstrdup (vbranch); - li->rev_old = li->rev_new = NULL; - p->data = li; - (void) addnode (ulist, p); - Update_Logfile (repository, message, logfp, ulist); - dellist (&ulist); - if (fclose (logfp) < 0) - error (0, errno, "error closing %s", tmpfile); - - /* Make sure the temporary file goes away, even on systems that don't let - you delete a file that's in use. */ - if (CVS_UNLINK (tmpfile) < 0 && !existence_error (errno)) - error (0, errno, "cannot remove %s", tmpfile); - free (tmpfile); - - if (message) - free (message); - free (repository); - free (vbranch); - free (vhead); - - return (err); -} - -/* Process all the files in ".", then descend into other directories. - Returns 0 for success, or >0 on error (in which case a message - will have been printed). */ -static int -import_descend (message, vtag, targc, targv) - char *message; - char *vtag; - int targc; - char *targv[]; -{ - DIR *dirp; - struct dirent *dp; - int err = 0; - List *dirlist = NULL; - - /* first, load up any per-directory ignore lists */ - ign_add_file (CVSDOTIGNORE, 1); - wrap_add_file (CVSDOTWRAPPER, 1); - - if (!current_parsed_root->isremote) - lock_dir_for_write (repository); - - if ((dirp = CVS_OPENDIR (".")) == NULL) - { - error (0, errno, "cannot open directory"); - err++; - } - else - { - errno = 0; - while ((dp = CVS_READDIR (dirp)) != NULL) - { - if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0) - goto one_more_time_boys; - - /* CVS directories are created in the temp directory by - server.c because it doesn't special-case import. So - don't print a message about them, regardless of -I!. */ - if (server_active && strcmp (dp->d_name, CVSADM) == 0) - goto one_more_time_boys; - - if (ign_name (dp->d_name)) - { - add_log ('I', dp->d_name); - goto one_more_time_boys; - } - - if ( -#ifdef DT_DIR - (dp->d_type == DT_DIR - || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name))) -#else - isdir (dp->d_name) -#endif - && !wrap_name_has (dp->d_name, WRAP_TOCVS) - ) - { - Node *n; - - if (dirlist == NULL) - dirlist = getlist(); - - n = getnode(); - n->key = xstrdup (dp->d_name); - addnode(dirlist, n); - } - else if ( -#ifdef DT_DIR - dp->d_type == DT_LNK - || (dp->d_type == DT_UNKNOWN && islink (dp->d_name)) -#else - islink (dp->d_name) -#endif - ) - { - add_log ('L', dp->d_name); - err++; - } - else - { -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - err += client_process_import_file (message, dp->d_name, - vtag, targc, targv, - repository, - keyword_opt != NULL && - keyword_opt[0] == 'b', - use_file_modtime); - else -#endif - err += process_import_file (message, dp->d_name, - vtag, targc, targv); - } - one_more_time_boys: - errno = 0; - } - if (errno != 0) - { - error (0, errno, "cannot read directory"); - ++err; - } - (void) CVS_CLOSEDIR (dirp); - } - - if (!current_parsed_root->isremote) - Lock_Cleanup (); - - if (dirlist != NULL) - { - Node *head, *p; - - head = dirlist->list; - for (p = head->next; p != head; p = p->next) - { - err += import_descend_dir (message, p->key, vtag, targc, targv); - } - - dellist(&dirlist); - } - - return (err); -} - -/* - * Process the argument import file. - */ -static int -process_import_file (message, vfile, vtag, targc, targv) - char *message; - char *vfile; - char *vtag; - int targc; - char *targv[]; -{ - char *rcs; - int inattic = 0; - - rcs = xmalloc (strlen (repository) + strlen (vfile) + sizeof (RCSEXT) - + 5); - (void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT); - if (!isfile (rcs)) - { - char *attic_name; - - attic_name = xmalloc (strlen (repository) + strlen (vfile) + - sizeof (CVSATTIC) + sizeof (RCSEXT) + 10); - (void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC, - vfile, RCSEXT); - if (!isfile (attic_name)) - { - int retval; - char *free_opt = NULL; - char *our_opt = keyword_opt; - - free (attic_name); - /* - * A new import source file; it doesn't exist as a ,v within the - * repository nor in the Attic -- create it anew. - */ - add_log ('N', vfile); - -#ifdef SERVER_SUPPORT - /* The most reliable information on whether the file is binary - is what the client told us. That is because if the client had - the wrong idea about binaryness, it corrupted the file, so - we might as well believe the client. */ - if (server_active) - { - Node *node; - List *entries; - - /* Reading all the entries for each file is fairly silly, and - probably slow. But I am too lazy at the moment to do - anything else. */ - entries = Entries_Open (0, NULL); - node = findnode_fn (entries, vfile); - if (node != NULL) - { - Entnode *entdata = node->data; - - if (entdata->type == ENT_FILE) - { - assert (entdata->options[0] == '-' - && entdata->options[1] == 'k'); - our_opt = xstrdup (entdata->options + 2); - free_opt = our_opt; - } - } - Entries_Close (entries); - } -#endif - - retval = add_rcs_file (message, rcs, vfile, vhead, our_opt, - vbranch, vtag, targc, targv, - NULL, 0, logfp); - if (free_opt != NULL) - free (free_opt); - free (rcs); - return retval; - } - free (attic_name); - inattic = 1; - } - - free (rcs); - /* - * an rcs file exists. have to do things the official, slow, way. - */ - return (update_rcs_file (message, vfile, vtag, targc, targv, inattic)); -} - -/* - * The RCS file exists; update it by adding the new import file to the - * (possibly already existing) vendor branch. - */ -static int -update_rcs_file (message, vfile, vtag, targc, targv, inattic) - char *message; - char *vfile; - char *vtag; - int targc; - char *targv[]; - int inattic; -{ - Vers_TS *vers; - int letter; - char *tocvsPath; - char *expand; - struct file_info finfo; - - memset (&finfo, 0, sizeof finfo); - finfo.file = vfile; - /* Not used, so don't worry about it. */ - finfo.update_dir = NULL; - finfo.fullname = finfo.file; - finfo.repository = repository; - finfo.entries = NULL; - finfo.rcs = NULL; - vers = Version_TS (&finfo, (char *) NULL, vbranch, (char *) NULL, - 1, 0); - if (vers->vn_rcs != NULL - && !RCS_isdead(vers->srcfile, vers->vn_rcs)) - { - int different; - - /* - * The rcs file does have a revision on the vendor branch. Compare - * this revision with the import file; if they match exactly, there - * is no need to install the new import file as a new revision to the - * branch. Just tag the revision with the new import tags. - * - * This is to try to cut down the number of "C" conflict messages for - * locally modified import source files. - */ - tocvsPath = wrap_tocvs_process_file (vfile); - /* FIXME: Why don't we pass tocvsPath to RCS_cmp_file if it is - not NULL? */ - expand = vers->srcfile->expand != NULL && - vers->srcfile->expand[0] == 'b' ? "-kb" : "-ko"; - different = RCS_cmp_file( vers->srcfile, vers->vn_rcs, (char **)NULL, - (char *)NULL, expand, vfile ); - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - - if (!different) - { - int retval = 0; - - /* - * The two files are identical. Just update the tags, print the - * "U", signifying that the file has changed, but needs no - * attention, and we're done. - */ - if (add_tags (vers->srcfile, vfile, vtag, targc, targv)) - retval = 1; - add_log ('U', vfile); - freevers_ts (&vers); - return (retval); - } - } - - /* We may have failed to parse the RCS file; check just in case */ - if (vers->srcfile == NULL || - add_rev (message, vers->srcfile, vfile, vers->vn_rcs) || - add_tags (vers->srcfile, vfile, vtag, targc, targv)) - { - freevers_ts (&vers); - return (1); - } - - if (vers->srcfile->branch == NULL || inattic || - strcmp (vers->srcfile->branch, vbranch) != 0) - { - conflicts++; - letter = 'C'; - } - else - letter = 'U'; - add_log (letter, vfile); - - freevers_ts (&vers); - return (0); -} - -/* - * Add the revision to the vendor branch - */ -static int -add_rev (message, rcs, vfile, vers) - char *message; - RCSNode *rcs; - char *vfile; - char *vers; -{ - int locked, status, ierrno; - char *tocvsPath; - - if (noexec) - return (0); - - locked = 0; - if (vers != NULL) - { - /* Before RCS_lock existed, we were directing stdout, as well as - stderr, from the RCS command, to DEVNULL. I wouldn't guess that - was necessary, but I don't know for sure. */ - /* Earlier versions of this function printed a `fork failed' error - when RCS_lock returned an error code. That's not appropriate - now that RCS_lock is librarified, but should the error text be - preserved? */ - if (RCS_lock (rcs, vbranch, 1) != 0) - return 1; - locked = 1; - RCS_rewrite (rcs, NULL, NULL); - } - tocvsPath = wrap_tocvs_process_file (vfile); - - status = RCS_checkin (rcs, tocvsPath == NULL ? vfile : tocvsPath, - message, vbranch, 0, - (RCS_FLAGS_QUIET | RCS_FLAGS_KEEPFILE - | (use_file_modtime ? RCS_FLAGS_MODTIME : 0))); - ierrno = errno; - - if ((tocvsPath != NULL) && (unlink_file_dir (tocvsPath) < 0)) - error (0, errno, "cannot remove %s", tocvsPath); - - if (status) - { - if (!noexec) - { - 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); - } - if (locked) - { - (void) RCS_unlock(rcs, vbranch, 0); - RCS_rewrite (rcs, NULL, NULL); - } - return (1); - } - return (0); -} - -/* - * Add the vendor branch tag and all the specified import release tags to the - * RCS file. The vendor branch tag goes on the branch root (1.1.1) while the - * vendor release tags go on the newly added leaf of the branch (1.1.1.1, - * 1.1.1.2, ...). - */ -static int -add_tags (rcs, vfile, vtag, targc, targv) - RCSNode *rcs; - char *vfile; - char *vtag; - int targc; - char *targv[]; -{ - int i, ierrno; - Vers_TS *vers; - int retcode = 0; - struct file_info finfo; - - if (noexec) - return (0); - - if ((retcode = RCS_settag(rcs, vtag, vbranch)) != 0) - { - ierrno = errno; - 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); - } - RCS_rewrite (rcs, NULL, NULL); - - memset (&finfo, 0, sizeof finfo); - finfo.file = vfile; - /* Not used, so don't worry about it. */ - finfo.update_dir = NULL; - finfo.fullname = finfo.file; - finfo.repository = repository; - finfo.entries = NULL; - finfo.rcs = NULL; - vers = Version_TS (&finfo, NULL, vtag, NULL, 1, 0); - for (i = 0; i < targc; i++) - { - if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) == 0) - RCS_rewrite (rcs, NULL, NULL); - else - { - ierrno = errno; - 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); - } - } - freevers_ts (&vers); - return (0); -} - -/* - * Stolen from rcs/src/rcsfnms.c, and adapted/extended. - */ -struct compair -{ - char *suffix, *comlead; -}; - -static const struct compair comtable[] = -{ - -/* - * comtable pairs each filename suffix with a comment leader. The comment - * leader is placed before each line generated by the $Log keyword. This - * table is used to guess the proper comment leader from the working file's - * suffix during initial ci (see InitAdmin()). Comment leaders are needed for - * languages without multiline comments; for others they are optional. - * - * I believe that the comment leader is unused if you are using RCS 5.7, which - * decides what leader to use based on the text surrounding the $Log keyword - * rather than a specified comment leader. - */ - {"a", "-- "}, /* Ada */ - {"ada", "-- "}, - {"adb", "-- "}, - {"asm", ";; "}, /* assembler (MS-DOS) */ - {"ads", "-- "}, /* Ada */ - {"bas", "' "}, /* Visual Basic code */ - {"bat", ":: "}, /* batch (MS-DOS) */ - {"body", "-- "}, /* Ada */ - {"c", " * "}, /* C */ - {"c++", "// "}, /* C++ in all its infinite guises */ - {"cc", "// "}, - {"cpp", "// "}, - {"cxx", "// "}, - {"m", "// "}, /* Objective-C */ - {"cl", ";;; "}, /* Common Lisp */ - {"cmd", ":: "}, /* command (OS/2) */ - {"cmf", "c "}, /* CM Fortran */ - {"cs", " * "}, /* C* */ - {"csh", "# "}, /* shell */ - {"dlg", " * "}, /* MS Windows dialog file */ - {"e", "# "}, /* efl */ - {"epsf", "% "}, /* encapsulated postscript */ - {"epsi", "% "}, /* encapsulated postscript */ - {"el", "; "}, /* Emacs Lisp */ - {"f", "c "}, /* Fortran */ - {"for", "c "}, - {"frm", "' "}, /* Visual Basic form */ - {"h", " * "}, /* C-header */ - {"hh", "// "}, /* C++ header */ - {"hpp", "// "}, - {"hxx", "// "}, - {"in", "# "}, /* for Makefile.in */ - {"l", " * "}, /* lex (conflict between lex and - * franzlisp) */ - {"mac", ";; "}, /* macro (DEC-10, MS-DOS, PDP-11, - * VMS, etc) */ - {"mak", "# "}, /* makefile, e.g. Visual C++ */ - {"me", ".\\\" "}, /* me-macros t/nroff */ - {"ml", "; "}, /* mocklisp */ - {"mm", ".\\\" "}, /* mm-macros t/nroff */ - {"ms", ".\\\" "}, /* ms-macros t/nroff */ - {"man", ".\\\" "}, /* man-macros t/nroff */ - {"1", ".\\\" "}, /* feeble attempt at man pages... */ - {"2", ".\\\" "}, - {"3", ".\\\" "}, - {"4", ".\\\" "}, - {"5", ".\\\" "}, - {"6", ".\\\" "}, - {"7", ".\\\" "}, - {"8", ".\\\" "}, - {"9", ".\\\" "}, - {"p", " * "}, /* pascal */ - {"pas", " * "}, - {"pl", "# "}, /* perl (conflict with Prolog) */ - {"ps", "% "}, /* postscript */ - {"psw", "% "}, /* postscript wrap */ - {"pswm", "% "}, /* postscript wrap */ - {"r", "# "}, /* ratfor */ - {"rc", " * "}, /* Microsoft Windows resource file */ - {"red", "% "}, /* psl/rlisp */ -#ifdef sparc - {"s", "! "}, /* assembler */ -#endif -#ifdef mc68000 - {"s", "| "}, /* assembler */ -#endif -#ifdef pdp11 - {"s", "/ "}, /* assembler */ -#endif -#ifdef vax - {"s", "# "}, /* assembler */ -#endif -#ifdef __ksr__ - {"s", "# "}, /* assembler */ - {"S", "# "}, /* Macro assembler */ -#endif - {"sh", "# "}, /* shell */ - {"sl", "% "}, /* psl */ - {"spec", "-- "}, /* Ada */ - {"tex", "% "}, /* tex */ - {"y", " * "}, /* yacc */ - {"ye", " * "}, /* yacc-efl */ - {"yr", " * "}, /* yacc-ratfor */ - {"", "# "}, /* default for empty suffix */ - {NULL, "# "} /* default for unknown suffix; */ -/* must always be last */ -}; - -static char * -get_comment (user) - const char *user; -{ - char *cp, *suffix; - char *suffix_path; - int i; - char *retval; - - suffix_path = xmalloc (strlen (user) + 5); - cp = strrchr (user, '.'); - if (cp != NULL) - { - cp++; - - /* - * Convert to lower-case, since we are not concerned about the - * case-ness of the suffix. - */ - (void) strcpy (suffix_path, cp); - for (cp = suffix_path; *cp; cp++) - if (isupper ((unsigned char) *cp)) - *cp = tolower (*cp); - suffix = suffix_path; - } - else - suffix = ""; /* will use the default */ - for (i = 0;; i++) - { - if (comtable[i].suffix == NULL) - { - /* Default. Note we'll always hit this case before we - ever return NULL. */ - retval = comtable[i].comlead; - break; - } - if (strcmp (suffix, comtable[i].suffix) == 0) - { - retval = comtable[i].comlead; - break; - } - } - free (suffix_path); - return retval; -} - -/* Create a new RCS file from scratch. - - This probably should be moved to rcs.c now that it is called from - places outside import.c. - - Return value is 0 for success, or nonzero for failure (in which - case an error message will have already been printed). */ -int -add_rcs_file (message, rcs, user, add_vhead, key_opt, - add_vbranch, vtag, targc, targv, - desctext, desclen, add_logfp) - /* Log message for the addition. Not used if add_vhead == NULL. */ - const char *message; - /* Filename of the RCS file to create. */ - const char *rcs; - /* Filename of the file to serve as the contents of the initial - revision. Even if add_vhead is NULL, we use this to determine - the modes to give the new RCS file. */ - const char *user; - - /* Revision number of head that we are adding. Normally 1.1 but - could be another revision as long as ADD_VBRANCH is a branch - from it. If NULL, then just add an empty file without any - revisions (similar to the one created by "rcs -i"). */ - const char *add_vhead; - - /* Keyword expansion mode, e.g., "b" for binary. NULL means the - default behavior. */ - const char *key_opt; - - /* Vendor branch to import to, or NULL if none. If non-NULL, then - vtag should also be non-NULL. */ - const char *add_vbranch; - const char *vtag; - int targc; - char *targv[]; - - /* If non-NULL, description for the file. If NULL, the description - will be empty. */ - const char *desctext; - size_t desclen; - - /* Write errors to here as well as via error (), or NULL if we should - use only error (). */ - FILE *add_logfp; -{ - FILE *fprcs, *fpuser; - struct stat sb; - struct tm *ftm; - time_t now; - char altdate1[MAXDATELEN]; - char *author; - int i, ierrno, err = 0; - mode_t mode; - char *tocvsPath; - const char *userfile; - char *free_opt = NULL; - mode_t file_type; - - if (noexec) - return (0); - - /* Note that as the code stands now, the -k option overrides any - settings in wrappers (whether CVSROOT/cvswrappers, -W, or - whatever). Some have suggested this should be the other way - around. As far as I know the documentation doesn't say one way - or the other. Before making a change of this sort, should think - about what is best, document it (in cvs.texinfo and NEWS), &c. */ - - if (key_opt == NULL) - { - if (wrap_name_has (user, WRAP_RCSOPTION)) - { - key_opt = free_opt = wrap_rcsoption (user, 0); - } - } - - tocvsPath = wrap_tocvs_process_file (user); - userfile = (tocvsPath == NULL ? user : tocvsPath); - - /* Opening in text mode is probably never the right thing for the - server (because the protocol encodes text files in a fashion - which does not depend on what the client or server OS is, as - documented in cvsclient.texi), but as long as the server just - runs on unix it is a moot point. */ - - /* If PreservePermissions is set, then make sure that the file - is a plain file before trying to open it. Longstanding (although - often unpopular) CVS behavior has been to follow symlinks, so we - maintain that behavior if PreservePermissions is not on. - - NOTE: this error message used to be `cannot fstat', but is now - `cannot lstat'. I don't see a way around this, since we must - stat the file before opening it. -twp */ - - if (CVS_LSTAT (userfile, &sb) < 0) - { - /* 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; - if (!preserve_perms || file_type == S_IFREG) - { - fpuser = CVS_FOPEN (userfile, - ((key_opt != NULL && strcmp (key_opt, "b") == 0) - ? "rb" - : "r") - ); - if (fpuser == NULL) - { - /* not fatal, continue import */ - if (add_logfp != NULL) - fperrmsg (add_logfp, 0, errno, - "ERROR: cannot read file %s", userfile); - error (0, errno, "ERROR: cannot read file %s", userfile); - goto read_error; - } - } - - fprcs = CVS_FOPEN (rcs, "w+b"); - if (fprcs == NULL) - { - ierrno = errno; - goto write_error_noclose; - } - - /* - * putadmin() - */ - if (add_vhead != NULL) - { - if (fprintf (fprcs, "head %s;\012", add_vhead) < 0) - goto write_error; - } - else - { - if (fprintf (fprcs, "head ;\012") < 0) - goto write_error; - } - - if (add_vbranch != NULL) - { - if (fprintf (fprcs, "branch %s;\012", add_vbranch) < 0) - goto write_error; - } - if (fprintf (fprcs, "access ;\012") < 0 || - fprintf (fprcs, "symbols ") < 0) - { - goto write_error; - } - - for (i = targc - 1; i >= 0; i--) - { - /* RCS writes the symbols backwards */ - assert (add_vbranch != NULL); - if (fprintf (fprcs, "%s:%s.1 ", targv[i], add_vbranch) < 0) - goto write_error; - } - - if (add_vbranch != NULL) - { - if (fprintf (fprcs, "%s:%s", vtag, add_vbranch) < 0) - goto write_error; - } - if (fprintf (fprcs, ";\012") < 0) - goto write_error; - - if (fprintf (fprcs, "locks ; strict;\012") < 0 || - /* XXX - make sure @@ processing works in the RCS file */ - fprintf (fprcs, "comment @%s@;\012", get_comment (user)) < 0) - { - goto write_error; - } - - if (key_opt != NULL && strcmp (key_opt, "kv") != 0) - { - if (fprintf (fprcs, "expand @%s@;\012", key_opt) < 0) - { - goto write_error; - } - } - - if (fprintf (fprcs, "\012") < 0) - goto write_error; - - /* Write the revision(s), with the date and author and so on - (that is "delta" rather than "deltatext" from rcsfile(5)). */ - if (add_vhead != NULL) - { - if (use_file_modtime) - now = sb.st_mtime; - else - (void) time (&now); - ftm = gmtime (&now); - (void) sprintf (altdate1, DATEFORM, - ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), - ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, - ftm->tm_min, ftm->tm_sec); - author = getcaller (); - - if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 || - fprintf (fprcs, "date %s; author %s; state Exp;\012", - altdate1, author) < 0) - goto write_error; - - if (fprintf (fprcs, "branches") < 0) - goto write_error; - if (add_vbranch != NULL) - { - if (fprintf (fprcs, " %s.1", add_vbranch) < 0) - goto write_error; - } - if (fprintf (fprcs, ";\012") < 0) - goto write_error; - - if (fprintf (fprcs, "next ;\012") < 0) - goto write_error; - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - /* Store initial permissions if necessary. */ - if (preserve_perms) - { - if (file_type == S_IFLNK) - { - char *link = xreadlink (userfile); - if (fprintf (fprcs, "symlink\t@") < 0 || - expand_at_signs (link, strlen (link), fprcs) < 0 || - fprintf (fprcs, "@;\012") < 0) - goto write_error; - free (link); - } - else - { - if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0) - goto write_error; - if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0) - goto write_error; - if (fprintf (fprcs, "permissions\t%o;\012", - sb.st_mode & 07777) < 0) - goto write_error; - switch (file_type) - { - case S_IFREG: break; - case S_IFCHR: - case S_IFBLK: -#ifdef HAVE_STRUCT_STAT_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, - "can't import %s: unknown kind of special file", - userfile); - } - } - } -#endif - - if (add_vbranch != NULL) - { - if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 || - fprintf (fprcs, "date %s; author %s; state Exp;\012", - altdate1, author) < 0 || - fprintf (fprcs, "branches ;\012") < 0 || - fprintf (fprcs, "next ;\012") < 0) - goto write_error; - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - /* Store initial permissions if necessary. */ - if (preserve_perms) - { - if (file_type == S_IFLNK) - { - char *link = xreadlink (userfile); - if (fprintf (fprcs, "symlink\t@") < 0 || - expand_at_signs (link, strlen (link), fprcs) < 0 || - fprintf (fprcs, "@;\012") < 0) - goto write_error; - free (link); - } - else - { - if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 || - fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 || - fprintf (fprcs, "permissions\t%o;\012", - sb.st_mode & 07777) < 0) - goto write_error; - - switch (file_type) - { - case S_IFREG: break; - case S_IFCHR: - case S_IFBLK: -#ifdef HAVE_STRUCT_STAT_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, - "cannot import %s: special file of unknown type", - userfile); - } - } - } -#endif - - if (fprintf (fprcs, "\012") < 0) - goto write_error; - } - } - - /* Now write the description (possibly empty). */ - if (fprintf (fprcs, "\012desc\012") < 0 || - fprintf (fprcs, "@") < 0) - goto write_error; - if (desctext != NULL) - { - /* The use of off_t not size_t for the second argument is very - strange, since we are dealing with something which definitely - fits in memory. */ - if (expand_at_signs (desctext, (off_t) desclen, fprcs) < 0) - goto write_error; - } - if (fprintf (fprcs, "@\012\012\012") < 0) - goto write_error; - - /* Now write the log messages and contents for the revision(s) (that - is, "deltatext" rather than "delta" from rcsfile(5)). */ - if (add_vhead != NULL) - { - if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 || - fprintf (fprcs, "log\012@") < 0) - goto write_error; - if (add_vbranch != NULL) - { - /* We are going to put the log message in the revision on the - branch. So putting it here too seems kind of redundant, I - guess (and that is what CVS has always done, anyway). */ - if (fprintf (fprcs, "Initial revision\012") < 0) - goto write_error; - } - else - { - if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0) - goto write_error; - } - if (fprintf (fprcs, "@\012") < 0 || - fprintf (fprcs, "text\012@") < 0) - { - goto write_error; - } - - /* Now copy over the contents of the file, expanding at signs. - If preserve_perms is set, do this only for regular files. */ - if (!preserve_perms || file_type == S_IFREG) - { - char buf[8192]; - unsigned int len; - - while (1) - { - len = fread (buf, 1, sizeof buf, fpuser); - if (len == 0) - { - if (ferror (fpuser)) - error (1, errno, "cannot read file %s for copying", - user); - break; - } - if (expand_at_signs (buf, len, fprcs) < 0) - goto write_error; - } - } - if (fprintf (fprcs, "@\012\012") < 0) - goto write_error; - if (add_vbranch != NULL) - { - if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 || - fprintf (fprcs, "log\012@") < 0 || - expand_at_signs (message, - (off_t) strlen (message), fprcs) < 0 || - fprintf (fprcs, "@\012text\012") < 0 || - fprintf (fprcs, "@@\012") < 0) - goto write_error; - } - } - - if (fclose (fprcs) == EOF) - { - ierrno = errno; - goto write_error_noclose; - } - /* Close fpuser only if we opened it to begin with. */ - if (fpuser != NULL) - { - if (fclose (fpuser) < 0) - error (0, errno, "cannot close %s", user); - } - - /* - * Fix the modes on the RCS files. The user modes of the original - * user file are propagated to the group and other modes as allowed - * by the repository umask, except that all write permissions are - * turned off. - */ - mode = (sb.st_mode | - (sb.st_mode & S_IRWXU) >> 3 | - (sb.st_mode & S_IRWXU) >> 6) & - ~cvsumask & - ~(S_IWRITE | S_IWGRP | S_IWOTH); - if (chmod (rcs, mode) < 0) - { - ierrno = errno; - if (add_logfp != NULL) - 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++; - } - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - if (free_opt != NULL) - free (free_opt); - return (err); - -write_error: - ierrno = errno; - if (fclose (fprcs) < 0) - error (0, errno, "cannot close %s", rcs); -write_error_noclose: - if (fclose (fpuser) < 0) - error (0, errno, "cannot close %s", user); - if (add_logfp != NULL) - 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) - fperrmsg (add_logfp, 0, 0, "ERROR: out of space - aborting"); - error (1, 0, "ERROR: out of space - aborting"); - } -read_error: - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - - if (free_opt != NULL) - free (free_opt); - - return (err + 1); -} - -/* - * Write SIZE bytes at BUF to FP, expanding @ signs into double @ - * signs. If an error occurs, return a negative value and set errno - * to indicate the error. If not, return a nonnegative value. - */ -int -expand_at_signs (buf, size, fp) - const char *buf; - off_t size; - FILE *fp; -{ - register const char *cp, *next; - - cp = buf; - while ((next = memchr (cp, '@', size)) != NULL) - { - size_t len = ++next - cp; - if (fwrite (cp, 1, len, fp) != len) - return EOF; - if (putc ('@', fp) == EOF) - return EOF; - cp = next; - size -= len; - } - - if (fwrite (cp, 1, size, fp) != size) - return EOF; - - return 1; -} - -/* - * Write an update message to (potentially) the screen and the log file. - */ -static void -add_log (ch, fname) - int ch; - char *fname; -{ - if (!really_quiet) /* write to terminal */ - { - char buf[2]; - buf[0] = ch; - buf[1] = ' '; - cvs_output (buf, 2); - if (repos_len) - { - cvs_output (repository + repos_len + 1, 0); - cvs_output ("/", 1); - } - else if (repository[0] != '\0') - { - cvs_output (repository, 0); - cvs_output ("/", 1); - } - cvs_output (fname, 0); - cvs_output ("\n", 1); - } - - if (repos_len) /* write to logfile */ - (void) fprintf (logfp, "%c %s/%s\n", ch, - repository + repos_len + 1, fname); - else if (repository[0]) - (void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname); - else - (void) fprintf (logfp, "%c %s\n", ch, fname); -} - -/* - * This is the recursive function that walks the argument directory looking - * for sub-directories that have CVS administration files in them and updates - * them recursively. - * - * Note that we do not follow symbolic links here, which is a feature! - */ -static int -import_descend_dir (message, dir, vtag, targc, targv) - char *message; - char *dir; - char *vtag; - int targc; - char *targv[]; -{ - struct saved_cwd cwd; - char *cp; - int ierrno, err; - char *rcs = NULL; - - if (islink (dir)) - return (0); - if (save_cwd (&cwd)) - { - fperrmsg (logfp, 0, 0, "ERROR: cannot get working directory"); - return (1); - } - - /* Concatenate DIR to the end of REPOSITORY. */ - if (repository[0] == '\0') - { - char *new = xstrdup (dir); - free (repository); - repository = new; - } - else - { - char *new = xmalloc (strlen (repository) + strlen (dir) + 10); - strcpy (new, repository); - (void) strcat (new, "/"); - (void) strcat (new, dir); - free (repository); - repository = new; - } - - if (!quiet && !current_parsed_root->isremote) - error (0, 0, "Importing %s", repository); - - if ( CVS_CHDIR (dir) < 0) - { - ierrno = errno; - fperrmsg (logfp, 0, ierrno, "ERROR: cannot chdir to %s", dir); - error (0, ierrno, "ERROR: cannot chdir to %s", dir); - err = 1; - goto out; - } - if (!current_parsed_root->isremote && !isdir (repository)) - { - rcs = xmalloc (strlen (repository) + sizeof (RCSEXT) + 5); - (void) sprintf (rcs, "%s%s", repository, RCSEXT); - if (isfile (repository) || isfile(rcs)) - { - 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; - goto out; - } - if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0) - { - ierrno = errno; - fperrmsg (logfp, 0, ierrno, - "ERROR: cannot mkdir %s -- not added", repository); - error (0, ierrno, - "ERROR: cannot mkdir %s -- not added", repository); - err = 1; - goto out; - } - } - err = import_descend (message, vtag, targc, targv); - out: - if (rcs != NULL) - free (rcs); - if ((cp = strrchr (repository, '/')) != NULL) - *cp = '\0'; - else - repository[0] = '\0'; - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - return (err); -} diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c deleted file mode 100644 index d8e78fa..0000000 --- a/contrib/cvs/src/lock.c +++ /dev/null @@ -1,1166 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Set Lock - * - * Lock file support for CVS. - * - * $FreeBSD$ - */ - -/* The node Concurrency in doc/cvs.texinfo has a brief introduction to - how CVS locks function, and some of the user-visible consequences of - their existence. Here is a summary of why they exist (and therefore, - the consequences of hacking CVS to read a repository without creating - locks): - - There are two uses. One is the ability to prevent there from being - two writers at the same time. This is necessary for any number of - reasons (fileattr code, probably others). Commit needs to lock the - whole tree so that nothing happens between the up-to-date check and - the actual checkin. - - The second use is the ability to ensure that there is not a writer - and a reader at the same time (several readers are allowed). Reasons - for this are: - - * Readlocks ensure that once CVS has found a collection of rcs - files using Find_Names, the files will still exist when it reads - them (they may have moved in or out of the attic). - - * Readlocks provide some modicum of consistency, although this is - kind of limited--see the node Concurrency in cvs.texinfo. - - * Readlocks ensure that the RCS file does not change between - RCS_parse and RCS_reparsercsfile time. This one strikes me as - important, although I haven't thought up what bad scenarios might - be. - - * Readlocks ensure that we won't find the file in the state in - which it is in between the calls to add_rcs_file and RCS_checkin in - commit.c (when a file is being added). This state is a state in - which the RCS file parsing routines in rcs.c cannot parse the file. - - * Readlocks ensure that a reader won't try to look at a - half-written fileattr file (fileattr is not updated atomically). - - (see also the description of anonymous read-only access in - "Password authentication security" node in doc/cvs.texinfo). - - While I'm here, I'll try to summarize a few random suggestions - which periodically get made about how locks might be different: - - 1. Check for EROFS. Maybe useful, although in the presence of NFS - EROFS does *not* mean that the file system is unchanging. - - 2. Provide an option to disable locks for operations which only - read (see above for some of the consequences). - - 3. Have a server internally do the locking. Probably a good - long-term solution, and many people have been working hard on code - changes which would eventually make it possible to have a server - which can handle various connections in one process, but there is - much, much work still to be done before this is feasible. */ - -#include "cvs.h" -#include <assert.h> - -#ifdef HAVE_NANOSLEEP -# include "xtime.h" -#else /* HAVE_NANOSLEEP */ -# if !defined HAVE_USLEEP && defined HAVE_SELECT - /* use select as a workaround */ -# include "xselect.h" -# endif /* !defined HAVE_USLEEP && defined HAVE_SELECT */ -#endif /* !HAVE_NANOSLEEP */ - - -struct lock { - /* This is the directory in which we may have a lock named by the - readlock variable, a lock named by the writelock variable, and/or - a lock named CVSLCK. The storage is not allocated along with the - struct lock; it is allocated by the Reader_Lock caller or in the - case of writelocks, it is just a pointer to the storage allocated - for the ->key field. */ - char *repository; - - /* The name of the master lock dir. Usually CVSLCK. */ - const char *lockdirname; - - /* The full path to the lock dir, if we are currently holding it. - * - * This will be LOCKDIRNAME catted onto REPOSITORY. We waste a little - * space by storing it, but save a later malloc/free. - */ - char *lockdir; - - /* Note there is no way of knowing whether the readlock and writelock - exist. The code which sets the locks doesn't use SIG_beginCrSect - to set a flag like we do for CVSLCK. */ -}; - -static void remove_locks PROTO((void)); -static int readers_exist PROTO((char *repository)); -static int set_lock PROTO ((struct lock *lock, int will_wait)); -static void clear_lock PROTO ((struct lock *lock)); -static void set_lockers_name PROTO((struct stat *statp)); -static int set_writelock_proc PROTO((Node * p, void *closure)); -static int unlock_proc PROTO((Node * p, void *closure)); -static int write_lock PROTO ((struct lock *lock)); -static void lock_simple_remove PROTO ((struct lock *lock)); -static void lock_wait PROTO((char *repository)); -static void lock_obtained PROTO((char *repository)); - -/* Malloc'd array containing the username of the whoever has the lock. - Will always be non-NULL in the cases where it is needed. */ -static char *lockers_name; -/* Malloc'd array specifying name of a readlock within a directory. - Or NULL if none. */ -static char *readlock; -/* Malloc'd array specifying name of a writelock within a directory. - Or NULL if none. */ -static char *writelock; -/* Malloc'd array specifying the name of a CVSLCK file (absolute pathname). - Will always be non-NULL in the cases where it is used. */ -static List *locklist; - -#define L_OK 0 /* success */ -#define L_ERROR 1 /* error condition */ -#define L_LOCKED 2 /* lock owned by someone else */ - -/* This is the (single) readlock which is set by Reader_Lock. The - repository field is NULL if there is no such lock. */ -static struct lock global_readlock = {NULL, CVSLCK, NULL}; - -static struct lock global_history_lock = {NULL, CVSHISTORYLCK, NULL}; -static struct lock global_val_tags_lock = {NULL, CVSVALTAGSLCK, NULL}; - -/* List of locks set by lock_tree_for_write. This is redundant - with locklist, sort of. */ -static List *lock_tree_list; - -/* If we set locks with lock_dir_for_write, then locked_dir contains - the malloc'd name of the repository directory which we have locked. - locked_list is the same thing packaged into a list and is redundant - with locklist the same way that lock_tree_list is. */ -static char *locked_dir; -static List *locked_list; - -/* LockDir from CVSROOT/config. */ -char *lock_dir; - -static char *lock_name PROTO ((const char *repository, const char *name)); - -/* Return a newly malloc'd string containing the name of the lock for the - repository REPOSITORY and the lock file name within that directory - NAME. Also create the directories in which to put the lock file - if needed (if we need to, could save system call(s) by doing - that only if the actual operation fails. But for now we'll keep - things simple). */ -static char * -lock_name (repository, name) - const char *repository; - const char *name; -{ - char *retval; - const char *p; - char *q; - const char *short_repos; - mode_t save_umask = 0; - int saved_umask = 0; - - if (lock_dir == NULL) - { - /* This is the easy case. Because the lock files go directly - in the repository, no need to create directories or anything. */ - retval = xmalloc (strlen (repository) + strlen (name) + 10); - (void) sprintf (retval, "%s/%s", repository, name); - } - else - { - struct stat sb; - mode_t new_mode = 0; - - /* The interesting part of the repository is the part relative - to CVSROOT. */ - assert (current_parsed_root != NULL); - assert (current_parsed_root->directory != NULL); - assert (strncmp (repository, current_parsed_root->directory, - strlen (current_parsed_root->directory)) == 0); - short_repos = repository + strlen (current_parsed_root->directory) + 1; - - if (strcmp (repository, current_parsed_root->directory) == 0) - short_repos = "."; - else - assert (short_repos[-1] == '/'); - - retval = xmalloc (strlen (lock_dir) - + strlen (short_repos) - + strlen (name) - + 10); - strcpy (retval, lock_dir); - q = retval + strlen (retval); - *q++ = '/'; - - strcpy (q, short_repos); - - /* In the common case, where the directory already exists, let's - keep it to one system call. */ - if (CVS_STAT (retval, &sb) < 0) - { - /* If we need to be creating more than one directory, we'll - get the existence_error here. */ - if (!existence_error (errno)) - error (1, errno, "cannot stat directory %s", retval); - } - else - { - if (S_ISDIR (sb.st_mode)) - goto created; - else - error (1, 0, "%s is not a directory", retval); - } - - /* Now add the directories one at a time, so we can create - them if needed. - - The idea behind the new_mode stuff is that the directory we - end up creating will inherit permissions from its parent - directory (we re-set new_mode with each EEXIST). CVSUMASK - isn't right, because typically the reason for LockDir is to - use a different set of permissions. We probably want to - inherit group ownership also (but we don't try to deal with - that, some systems do it for us either always or when g+s is on). - - We don't try to do anything about the permissions on the lock - files themselves. The permissions don't really matter so much - because the locks will generally be removed by the process - which created them. */ - - if (CVS_STAT (lock_dir, &sb) < 0) - error (1, errno, "cannot stat %s", lock_dir); - new_mode = sb.st_mode; - save_umask = umask (0000); - saved_umask = 1; - - p = short_repos; - while (1) - { - while (!ISDIRSEP (*p) && *p != '\0') - ++p; - if (ISDIRSEP (*p)) - { - strncpy (q, short_repos, p - short_repos); - q[p - short_repos] = '\0'; - if (!ISDIRSEP (q[p - short_repos - 1]) - && CVS_MKDIR (retval, new_mode) < 0) - { - int saved_errno = errno; - if (saved_errno != EEXIST) - error (1, errno, "cannot make directory %s", retval); - else - { - if (CVS_STAT (retval, &sb) < 0) - error (1, errno, "cannot stat %s", retval); - new_mode = sb.st_mode; - } - } - ++p; - } - else - { - strcpy (q, short_repos); - if (CVS_MKDIR (retval, new_mode) < 0 - && errno != EEXIST) - error (1, errno, "cannot make directory %s", retval); - goto created; - } - } - created:; - - strcat (retval, "/"); - strcat (retval, name); - - if (saved_umask) - { - assert (umask (save_umask) == 0000); - saved_umask = 0; - } - } - return retval; -} - -/* - * Clean up all outstanding locks - */ -void -Lock_Cleanup () -{ - /* FIXME: error handling here is kind of bogus; we sometimes will call - error, which in turn can call us again. For the moment work around - this by refusing to reenter this function (this is a kludge). */ - /* FIXME-reentrancy: the workaround isn't reentrant. */ - static int in_lock_cleanup = 0; - - if (trace) - (void) fprintf (stderr, "%s-> Lock_Cleanup()\n", CLIENT_SERVER_STR); - - if (in_lock_cleanup) - return; - in_lock_cleanup = 1; - - remove_locks (); - - dellist (&lock_tree_list); - - if (locked_dir != NULL) - { - dellist (&locked_list); - free (locked_dir); - locked_dir = NULL; - locked_list = NULL; - } - - if (global_history_lock.repository) clear_history_lock (); - if (global_val_tags_lock.repository) clear_val_tags_lock (); - - in_lock_cleanup = 0; -} - -/* - * Remove locks without discarding the lock information - */ -static void -remove_locks () -{ - /* clean up simple locks (if any) */ - if (global_readlock.repository != NULL) - { - lock_simple_remove (&global_readlock); - global_readlock.repository = NULL; - } - - /* clean up multiple locks (if any) */ - if (locklist != (List *) NULL) - { - (void) walklist (locklist, unlock_proc, NULL); - locklist = (List *) NULL; - } -} - -/* - * walklist proc for removing a list of locks - */ -static int -unlock_proc (p, closure) - Node *p; - void *closure; -{ - lock_simple_remove (p->data); - return (0); -} - - - -/* Remove the lock files. */ -static void -lock_simple_remove (lock) - struct lock *lock; -{ - char *tmp; - - /* If readlock is set, the lock directory *might* have been created, but - since Reader_Lock doesn't use SIG_beginCrSect the way that set_lock - does, we don't know that. That is why we need to check for - existence_error here. */ - if (readlock != NULL) - { - tmp = lock_name (lock->repository, readlock); - if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) - error (0, errno, "failed to remove lock %s", tmp); - free (tmp); - } - - /* If writelock is set, the lock directory *might* have been created, but - since write_lock doesn't use SIG_beginCrSect the way that set_lock - does, we don't know that. That is why we need to check for - existence_error here. */ - if (writelock != NULL) - { - tmp = lock_name (lock->repository, writelock); - if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) - error (0, errno, "failed to remove lock %s", tmp); - free (tmp); - } - - clear_lock (lock); -} - - - -/* - * Create a lock file for readers - */ -int -Reader_Lock (xrepository) - char *xrepository; -{ - int err = 0; - FILE *fp; - char *tmp; - - if (trace) - (void) fprintf (stderr, "%s-> Reader_Lock(%s)\n", CLIENT_SERVER_STR, - xrepository); - - if (noexec || readonlyfs) - return 0; - - /* we only do one directory at a time for read locks! */ - if (global_readlock.repository != NULL) - { - error (0, 0, "Reader_Lock called while read locks set - Help!"); - return 1; - } - - if (readlock == NULL) - { - readlock = xmalloc (strlen (hostname) + sizeof (CVSRFL) + 40); - (void) sprintf (readlock, -#ifdef HAVE_LONG_FILE_NAMES - "%s.%s.%ld", CVSRFL, hostname, -#else - "%s.%ld", CVSRFL, -#endif - (long) getpid ()); - } - - /* remember what we're locking (for Lock_Cleanup) */ - global_readlock.repository = xrepository; - - /* get the lock dir for our own */ - if (set_lock (&global_readlock, 1) != L_OK) - { - error (0, 0, "failed to obtain dir lock in repository `%s'", - xrepository); - if (readlock != NULL) - free (readlock); - readlock = NULL; - /* We don't set global_readlock.repository to NULL. I think this - only works because recurse.c will give a fatal error if we return - a nonzero value. */ - return 1; - } - - /* write a read-lock */ - tmp = lock_name (xrepository, readlock); - if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) - { - error (0, errno, "cannot create read lock in repository `%s'", - xrepository); - if (readlock != NULL) - free (readlock); - readlock = NULL; - err = 1; - } - free (tmp); - - /* free the lock dir */ - clear_lock (&global_readlock); - - return err; -} - - - -/* - * Lock a list of directories for writing - */ -static char *lock_error_repos; -static int lock_error; - -static int Writer_Lock PROTO ((List * list)); - -static int -Writer_Lock (list) - List *list; -{ - char *wait_repos; - - if (noexec) - return 0; - - if (readonlyfs) { - error (0, 0, "write lock failed - read-only repository"); - return (1); - } - - /* We only know how to do one list at a time */ - if (locklist != (List *) NULL) - { - error (0, 0, "Writer_Lock called while write locks set - Help!"); - return 1; - } - - wait_repos = NULL; - for (;;) - { - /* try to lock everything on the list */ - lock_error = L_OK; /* init for set_writelock_proc */ - lock_error_repos = (char *) NULL; /* init for set_writelock_proc */ - locklist = list; /* init for Lock_Cleanup */ - if (lockers_name != NULL) - free (lockers_name); - lockers_name = xstrdup ("unknown"); - - (void) walklist (list, set_writelock_proc, NULL); - - switch (lock_error) - { - case L_ERROR: /* Real Error */ - if (wait_repos != NULL) - free (wait_repos); - Lock_Cleanup (); /* clean up any locks we set */ - error (0, 0, "lock failed - giving up"); - return 1; - - case L_LOCKED: /* Someone already had a lock */ - remove_locks (); /* clean up any locks we set */ - lock_wait (lock_error_repos); /* sleep a while and try again */ - wait_repos = xstrdup (lock_error_repos); - continue; - - case L_OK: /* we got the locks set */ - if (wait_repos != NULL) - { - lock_obtained (wait_repos); - free (wait_repos); - } - return 0; - - default: - if (wait_repos != NULL) - free (wait_repos); - error (0, 0, "unknown lock status %d in Writer_Lock", - lock_error); - return 1; - } - } -} - - - -/* - * walklist proc for setting write locks - */ -static int -set_writelock_proc (p, closure) - Node *p; - void *closure; -{ - /* if some lock was not OK, just skip this one */ - if (lock_error != L_OK) - return 0; - - /* apply the write lock */ - lock_error_repos = p->key; - lock_error = write_lock (p->data); - return 0; -} - - - -/* - * Create a lock file for writers returns L_OK if lock set ok, L_LOCKED if - * lock held by someone else or L_ERROR if an error occurred - */ -static int -write_lock (lock) - struct lock *lock; -{ - int status; - FILE *fp; - char *tmp; - - if (trace) - (void) fprintf (stderr, "%s-> write_lock(%s)\n", - CLIENT_SERVER_STR, lock->repository); - - if (writelock == NULL) - { - writelock = xmalloc (strlen (hostname) + sizeof (CVSWFL) + 40); - (void) sprintf (writelock, -#ifdef HAVE_LONG_FILE_NAMES - "%s.%s.%ld", CVSWFL, hostname, -#else - "%s.%ld", CVSWFL, -#endif - (long) getpid()); - } - - /* make sure the lock dir is ours (not necessarily unique to us!) */ - status = set_lock (lock, 0); - if (status == L_OK) - { - /* we now own a writer - make sure there are no readers */ - if (readers_exist (lock->repository)) - { - /* clean up the lock dir if we created it */ - if (status == L_OK) - { - clear_lock (lock); - } - - /* indicate we failed due to read locks instead of error */ - return L_LOCKED; - } - - /* write the write-lock file */ - tmp = lock_name (lock->repository, writelock); - if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) - { - int xerrno = errno; - - if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) - error (0, errno, "failed to remove lock %s", tmp); - - /* free the lock dir if we created it */ - if (status == L_OK) - { - clear_lock (lock); - } - - /* return the error */ - error (0, xerrno, "cannot create write lock in repository `%s'", - lock->repository); - free (tmp); - return L_ERROR; - } - free (tmp); - return L_OK; - } - else - return status; -} - - - -/* - * readers_exist() returns 0 if there are no reader lock files remaining in - * the repository; else 1 is returned, to indicate that the caller should - * sleep a while and try again. - */ -static int -readers_exist (repository) - char *repository; -{ - char *lockdir; - char *line; - DIR *dirp; - struct dirent *dp; - struct stat sb; - int ret; -#ifdef CVS_FUDGELOCKS - time_t now; - (void)time (&now); -#endif - - lockdir = lock_name (repository, ""); - - assert (lockdir != NULL); - - lockdir[strlen (lockdir) - 1] = '\0'; /* remove trailing slash */ - - do { - if ((dirp = CVS_OPENDIR (lockdir)) == NULL) - error (1, 0, "cannot open directory %s", lockdir); - - ret = 0; - errno = 0; - while ((dp = CVS_READDIR (dirp)) != NULL) - { - if (CVS_FNMATCH (CVSRFLPAT, dp->d_name, 0) == 0) - { - line = xmalloc (strlen (lockdir) + 1 + strlen (dp->d_name) + 1); - (void)sprintf (line, "%s/%s", lockdir, dp->d_name); - if (CVS_STAT (line, &sb) != -1) - { -#ifdef CVS_FUDGELOCKS - /* - * If the create time of the file is more than CVSLCKAGE - * seconds ago, try to clean-up the lock file, and if - * successful, re-open the directory and try again. - */ - if (now >= (sb.st_ctime + CVSLCKAGE) && - CVS_UNLINK (line) != -1) - { - free (line); - ret = -1; - break; - } -#endif - set_lockers_name (&sb); - } - else - { - /* If the file doesn't exist, it just means that it - * disappeared between the time we did the readdir and the - * time we did the stat. - */ - if (!existence_error (errno)) - error (0, errno, "cannot stat %s", line); - } - errno = 0; - free (line); - ret = 1; - break; - } - errno = 0; - } - if (errno != 0) - error (0, errno, "error reading directory %s", repository); - - CVS_CLOSEDIR (dirp); - } while (ret < 0); - - if (lockdir != NULL) - free (lockdir); - return ret; -} - - - -/* - * Set the static variable lockers_name appropriately, based on the stat - * structure passed in. - */ -static void -set_lockers_name (statp) - struct stat *statp; -{ - struct passwd *pw; - - if (lockers_name != NULL) - free (lockers_name); - if ((pw = (struct passwd *)getpwuid (statp->st_uid)) != - (struct passwd *)NULL) - { - lockers_name = xstrdup (pw->pw_name); - } - else - { - lockers_name = xmalloc (20); - (void)sprintf (lockers_name, "uid%lu", (unsigned long) statp->st_uid); - } -} - - - -/* - * Persistently tries to make the directory "lckdir", which serves as a - * lock. - * - * #ifdef CVS_FUDGELOCKS - * If the create time on the directory is greater than CVSLCKAGE - * seconds old, just try to remove the directory. - * #endif - * - */ -static int -set_lock (lock, will_wait) - struct lock *lock; - int will_wait; -{ - int waited; - long us; - struct stat sb; - mode_t omask; - char *masterlock; - int status; -#ifdef CVS_FUDGELOCKS - time_t now; -#endif - - masterlock = lock_name (lock->repository, lock->lockdirname); - - /* - * Note that it is up to the callers of set_lock() to arrange for signal - * handlers that do the appropriate things, like remove the lock - * directory before they exit. - */ - waited = 0; - us = 1; - for (;;) - { - status = -1; - omask = umask (cvsumask); - SIG_beginCrSect (); - if (CVS_MKDIR (masterlock, 0777) == 0) - { - lock->lockdir = masterlock; - SIG_endCrSect (); - status = L_OK; - if (waited) - lock_obtained (lock->repository); - goto after_sig_unblock; - } - SIG_endCrSect (); - after_sig_unblock: - (void) umask (omask); - if (status != -1) - goto done; - - if (errno != EEXIST) - { - error (0, errno, - "failed to create lock directory for `%s' (%s)", - lock->repository, masterlock); - status = L_ERROR; - goto done; - } - - /* Find out who owns the lock. If the lock directory is - non-existent, re-try the loop since someone probably just - removed it (thus releasing the lock). */ - if (CVS_STAT (masterlock, &sb) < 0) - { - if (existence_error (errno)) - continue; - - error (0, errno, "couldn't stat lock directory `%s'", masterlock); - status = L_ERROR; - goto done; - } - -#ifdef CVS_FUDGELOCKS - /* - * If the create time of the directory is more than CVSLCKAGE seconds - * ago, try to clean-up the lock directory, and if successful, just - * quietly retry to make it. - */ - (void) time (&now); - if (now >= (sb.st_ctime + CVSLCKAGE)) - { - if (CVS_RMDIR (masterlock) >= 0) - continue; - } -#endif - - /* set the lockers name */ - set_lockers_name (&sb); - - /* if he wasn't willing to wait, return an error */ - if (!will_wait) - { - status = L_LOCKED; - goto done; - } - - /* if possible, try a very short sleep without a message */ - if (!waited && us < 1000) - { - us += us; -#if defined HAVE_NANOSLEEP - { - struct timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = us * 1000; - (void)nanosleep (&ts, NULL); - continue; - } -#elif defined HAVE_USLEEP - (void)usleep (us); - continue; -#elif defined HAVE_SELECT - { - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = us; - (void)select (0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, &tv); - continue; - } -#endif - } - - lock_wait (lock->repository); - waited = 1; - } -done: - if (!lock->lockdir) free (masterlock); - return status; -} - - - -/* - * Clear master lock. - * - * INPUTS - * lock The lock information. - * - * OUTPUTS - * Sets LOCK->lockdir to NULL after removing the directory it names and - * freeing the storage. - * - * ASSUMPTIONS - * If we own the master lock directory, its name is stored in LOCK->lockdir. - * We may free LOCK->lockdir. - * - */ -static void -clear_lock (lock) - struct lock *lock; -{ - SIG_beginCrSect (); - if (lock->lockdir) - { - if (CVS_RMDIR (lock->lockdir) < 0) - error (0, errno, "failed to remove lock dir `%s'", lock->lockdir); - free (lock->lockdir); - lock->lockdir = NULL; - } - SIG_endCrSect (); -} - - - -/* - * Print out a message that the lock is still held, then sleep a while. - */ -static void -lock_wait (repos) - char *repos; -{ - time_t now; - char *msg; - struct tm *tm_p; - - (void) time (&now); - tm_p = gmtime (&now); - msg = xmalloc (100 + strlen (lockers_name) + strlen (repos)); - sprintf (msg, "[%8.8s] waiting for %s's lock in %s", - (tm_p ? asctime (tm_p) : ctime (&now)) + 11, - lockers_name, repos); - error (0, 0, "%s", msg); - /* Call cvs_flusherr to ensure that the user sees this message as - soon as possible. */ - cvs_flusherr (); - free (msg); - (void) sleep (CVSLCKSLEEP); -} - -/* - * Print out a message when we obtain a lock. - */ -static void -lock_obtained (repos) - char *repos; -{ - time_t now; - char *msg; - struct tm *tm_p; - - (void) time (&now); - tm_p = gmtime (&now); - msg = xmalloc (100 + strlen (repos)); - sprintf (msg, "[%8.8s] obtained lock in %s", - (tm_p ? asctime (tm_p) : ctime (&now)) + 11, repos); - error (0, 0, "%s", msg); - /* Call cvs_flusherr to ensure that the user sees this message as - soon as possible. */ - cvs_flusherr (); - free (msg); -} - - - -static int lock_filesdoneproc PROTO ((void *callerdat, int err, - const char *repository, - const char *update_dir, - List *entries)); - -/* - * Create a list of repositories to lock - */ -/* ARGSUSED */ -static int -lock_filesdoneproc (callerdat, err, repository, update_dir, entries) - void *callerdat; - int err; - const char *repository; - const char *update_dir; - List *entries; -{ - Node *p; - - p = getnode (); - p->type = LOCK; - p->key = xstrdup (repository); - p->data = xmalloc (sizeof (struct lock)); - ((struct lock *)p->data)->repository = p->key; - ((struct lock *)p->data)->lockdirname = CVSLCK; - ((struct lock *)p->data)->lockdir = NULL; - - /* FIXME-KRP: this error condition should not simply be passed by. */ - if (p->key == NULL || addnode (lock_tree_list, p) != 0) - freenode (p); - return (err); -} - -void -lock_tree_for_write (argc, argv, local, which, aflag) - int argc; - char **argv; - int local; - int which; - int aflag; -{ - /* - * Run the recursion processor to find all the dirs to lock and lock all - * the dirs - */ - lock_tree_list = getlist (); - start_recursion ((FILEPROC) NULL, lock_filesdoneproc, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, argc, - argv, local, which, aflag, CVS_LOCK_NONE, - (char *) NULL, 0, (char *) NULL); - sortlist (lock_tree_list, fsortcmp); - if (Writer_Lock (lock_tree_list) != 0) - error (1, 0, "lock failed - giving up"); -} - -/* Lock a single directory in REPOSITORY. It is OK to call this if - a lock has been set with lock_dir_for_write; the new lock will replace - the old one. If REPOSITORY is NULL, don't do anything. */ -void -lock_dir_for_write (repository) - char *repository; -{ - if (repository != NULL - && (locked_dir == NULL - || strcmp (locked_dir, repository) != 0)) - { - Node *node; - - if (locked_dir != NULL) - Lock_Cleanup (); - - locked_dir = xstrdup (repository); - locked_list = getlist (); - node = getnode (); - node->type = LOCK; - node->key = xstrdup (repository); - node->data = xmalloc (sizeof (struct lock)); - ((struct lock *)node->data)->repository = node->key; - ((struct lock *)node->data)->lockdirname = CVSLCK; - ((struct lock *)node->data)->lockdir = NULL; - - (void) addnode (locked_list, node); - Writer_Lock (locked_list); - } -} - - - -/* This is the internal implementation behind history_lock & val_tags_lock. It - * gets a write lock for the history or val-tags file. - * - * RETURNS - * true, on success - * false, on error - */ -static int internal_lock PROTO ((struct lock *lock, const char *xrepository)); -static int -internal_lock (lock, xrepository) - struct lock *lock; - const char *xrepository; -{ - /* remember what we're locking (for Lock_Cleanup) */ - assert (!lock->repository); - lock->repository = xmalloc (strlen (xrepository) + sizeof (CVSROOTADM) + 2); - sprintf (lock->repository, "%s/%s", xrepository, CVSROOTADM); - - /* get the lock dir for our own */ - if (set_lock (lock, 1) != L_OK) - { - if (!really_quiet) - error (0, 0, "failed to obtain history lock in repository `%s'", - xrepository); - - return 0; - } - - return 1; -} - - - -/* This is the internal implementation behind history_lock & val_tags_lock. It - * removes the write lock for the history or val-tags file, when it exists. - */ -static void internal_clear_lock PROTO((struct lock *lock)); -static void -internal_clear_lock (lock) - struct lock *lock; -{ - SIG_beginCrSect (); - if (lock->repository) - { - free (lock->repository); - lock->repository = NULL; - } - SIG_endCrSect (); - - clear_lock (lock); -} - - - -/* Lock the CVSROOT/history file for write. - */ -int -history_lock (xrepository) - const char *xrepository; -{ - return internal_lock (&global_history_lock, xrepository); -} - - - -/* Remove the CVSROOT/history lock, if it exists. - */ -void -clear_history_lock () -{ - internal_clear_lock (&global_history_lock); -} - - - -/* Lock the CVSROOT/val-tags file for write. - */ -int -val_tags_lock (xrepository) - const char *xrepository; -{ - return internal_lock (&global_val_tags_lock, xrepository); -} - - - -/* Remove the CVSROOT/val-tags lock, if it exists. - */ -void -clear_val_tags_lock () -{ - internal_clear_lock (&global_val_tags_lock); -} diff --git a/contrib/cvs/src/log.c b/contrib/cvs/src/log.c deleted file mode 100644 index 0bf44c7..0000000 --- a/contrib/cvs/src/log.c +++ /dev/null @@ -1,1818 +0,0 @@ -/* - * Copyright (C) 1986-2008 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Print Log Information - * - * Prints the RCS "log" (rlog) information for the specified files. With no - * argument, prints the log information for all the files in the directory - * (recursive by default). - * - * $FreeBSD$ - */ - -#include "cvs.h" -#include <assert.h> - -/* This structure holds information parsed from the -r option. */ - -struct option_revlist -{ - /* The next -r option. */ - struct option_revlist *next; - /* The first revision to print. This is NULL if the range is - :rev, or if no revision is given. */ - char *first; - /* The last revision to print. This is NULL if the range is rev:, - or if no revision is given. If there is no colon, first and - last are the same. */ - char *last; - /* Nonzero if there was a trailing `.', which means to print only - the head revision of a branch. */ - int branchhead; - /* Nonzero if first and last are inclusive. */ - int inclusive; -}; - -/* This structure holds information derived from option_revlist given - a particular RCS file. */ - -struct revlist -{ - /* The next pair. */ - struct revlist *next; - /* The first numeric revision to print. */ - char *first; - /* The last numeric revision to print. */ - char *last; - /* The number of fields in these revisions (one more than - numdots). */ - int fields; - /* Whether first & last are to be included or excluded. */ - int inclusive; -}; - -/* This structure holds information parsed from the -d option. */ - -struct datelist -{ - /* The next date. */ - struct datelist *next; - /* The starting date. */ - char *start; - /* The ending date. */ - char *end; - /* Nonzero if the range is inclusive rather than exclusive. */ - int inclusive; -}; - -/* This structure is used to pass information through start_recursion. */ -struct log_data -{ - /* Nonzero if the -R option was given, meaning that only the name - of the RCS file should be printed. */ - int nameonly; - /* Nonzero if the -h option was given, meaning that only header - information should be printed. */ - int header; - /* Nonzero if the -t option was given, meaning that only the - header and the descriptive text should be printed. */ - int long_header; - /* Nonzero if the -N option was seen, meaning that tag information - should not be printed. */ - int notags; - /* Nonzero if the -b option was seen, meaning that revisions - on the default branch should be printed. */ - int default_branch; - /* Nonzero if the -S option was seen, meaning that the header/name - should be suppressed if no revisions are selected. */ - int sup_header; - /* If not NULL, the value given for the -r option, which lists - sets of revisions to be printed. */ - struct option_revlist *revlist; - /* If not NULL, the date pairs given for the -d option, which - select date ranges to print. */ - struct datelist *datelist; - /* If not NULL, the single dates given for the -d option, which - select specific revisions to print based on a date. */ - struct datelist *singledatelist; - /* If not NULL, the list of states given for the -s option, which - only prints revisions of given states. */ - List *statelist; - /* If not NULL, the list of login names given for the -w option, - which only prints revisions checked in by given users. */ - List *authorlist; -}; - -/* This structure is used to pass information through walklist. */ -struct log_data_and_rcs -{ - struct log_data *log_data; - struct revlist *revlist; - RCSNode *rcs; -}; - -static int rlog_proc PROTO((int argc, char **argv, char *xwhere, - char *mwhere, char *mfile, int shorten, - int local_specified, char *mname, char *msg)); -static Dtype log_dirproc PROTO ((void *callerdat, const char *dir, - const char *repository, - const char *update_dir, - List *entries)); -static int log_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static struct option_revlist *log_parse_revlist PROTO ((const char *)); -static void log_parse_date PROTO ((struct log_data *, const char *)); -static void log_parse_list PROTO ((List **, const char *)); -static struct revlist *log_expand_revlist PROTO ((RCSNode *, char *, - struct option_revlist *, - int)); -static void log_free_revlist PROTO ((struct revlist *)); -static int log_version_requested PROTO ((struct log_data *, struct revlist *, - RCSNode *, RCSVers *)); -static int log_symbol PROTO ((Node *, void *)); -static int log_count PROTO ((Node *, void *)); -static int log_fix_singledate PROTO ((Node *, void *)); -static int log_count_print PROTO ((Node *, void *)); -static void log_tree PROTO ((struct log_data *, struct revlist *, - RCSNode *, const char *)); -static void log_abranch PROTO ((struct log_data *, struct revlist *, - RCSNode *, const char *)); -static void log_version PROTO ((struct log_data *, struct revlist *, - RCSNode *, RCSVers *, int)); -static int log_branch PROTO ((Node *, void *)); -static int version_compare PROTO ((const char *, const char *, int)); - -static struct log_data log_data; -static int is_rlog; - -static const char *const log_usage[] = -{ - "Usage: %s %s [-lRhtNb] [-r[revisions]] [-d dates] [-s states]\n", - " [-w[logins]] [files...]\n", - "\t-l\tLocal directory only, no recursion.\n", - "\t-b\tList revisions on the default branch.\n", - "\t-h\tOnly print header.\n", - "\t-R\tOnly print name of RCS file.\n", - "\t-t\tOnly print header and descriptive text.\n", - "\t-N\tDo not list tags.\n", - "\t-n\tList tags (default).\n", - "\t-S\tDo not print name/header if no revisions selected. -d, -r,\n", - "\t\t-s, & -w have little effect in conjunction with -b, -h, -R, and\n", - "\t\t-t without this option.\n", - "\t-r[revisions]\tA comma-separated list of revisions to print:\n", - "\t rev1:rev2 Between rev1 and rev2, including rev1 and rev2.\n", - "\t rev1::rev2 Between rev1 and rev2, excluding rev1.\n", - "\t rev: rev and following revisions on the same branch.\n", - "\t rev:: After rev on the same branch.\n", - "\t :rev rev and previous revisions on the same branch.\n", - "\t ::rev rev and previous revisions on the same branch.\n", - "\t rev Just rev.\n", - "\t branch All revisions on the branch.\n", - "\t branch. The last revision on the branch.\n", - "\t-d dates\tA semicolon-separated list of dates\n", - "\t \t(D1<D2 for range, D for latest before).\n", - "\t-s states\tOnly list revisions with specified states.\n", - "\t-w[logins]\tOnly list revisions checked in by specified logins.\n", - "(Specify the --help global option for a list of other help options)\n", - 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; - char **argv; -{ - int c; - int err = 0; - int local = 0; - struct option_revlist **prl; - - is_rlog = (strcmp (cvs_cmd_name, "rlog") == 0); - - 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:hlNnSRr::s:tw::")) != -1) - { - switch (c) - { - case 'b': - log_data.default_branch = 1; - break; - case 'd': - log_parse_date (&log_data, optarg); - break; - case 'h': - log_data.header = 1; - break; - case 'l': - local = 1; - break; - case 'N': - log_data.notags = 1; - break; - case 'n': - log_data.notags = 0; - break; - case 'S': - log_data.sup_header = 1; - break; - case 'R': - log_data.nameonly = 1; - break; - case 'r': - *prl = log_parse_revlist (optarg); - prl = &(*prl)->next; - break; - case 's': - log_parse_list (&log_data.statelist, optarg); - break; - case 't': - log_data.long_header = 1; - break; - case 'w': - if (optarg != NULL) - log_parse_list (&log_data.authorlist, optarg); - else - log_parse_list (&log_data.authorlist, "@@MYSELF"); - break; - case '?': - default: - usage (log_usage); - break; - } - } - argc -= optind; - argv += optind; - - wrap_setup (); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - struct datelist *p; - struct option_revlist *rp; - char datetmp[MAXDATELEN]; - - /* We're the local client. Fire up the remote server. */ - start_server (); - - if (is_rlog && !supported_request ("rlog")) - error (1, 0, "server does not support rlog"); - - ign_setup (); - - if (log_data.default_branch) - send_arg ("-b"); - - while (log_data.datelist != NULL) - { - p = log_data.datelist; - log_data.datelist = p->next; - assert (p->start != NULL && p->end != NULL); - 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); - free (p->start); - free (p->end); - free (p); - } - while (log_data.singledatelist != NULL) - { - p = log_data.singledatelist; - log_data.singledatelist = p->next; - assert (p->end != NULL); - 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); - 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.sup_header) - send_arg("-S"); - 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->inclusive) - 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_arg ("--"); - - if (is_rlog) - { - int i; - for (i = 0; i < argc; i++) - send_arg (argv[i]); - send_to_server ("rlog\012", 0); - } - else - { - send_files (argc, argv, local, 0, SEND_NO_CONTENTS); - send_file_names (argc, argv, SEND_EXPAND_WILD); - send_to_server ("log\012", 0); - } - err = get_responses_and_close (); - return err; - } -#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 ()); - - if (is_rlog) - { - DBM *db; - int i; - db = open_module (); - for (i = 0; i < argc; i++) - { - err += do_module (db, argv[i], MISC, "Logging", rlog_proc, - (char *) NULL, 0, local, 0, 0, (char *) NULL); - } - close_module (db); - } - else - { - err = rlog_proc (argc + 1, argv - 1, (char *) NULL, - (char *) NULL, (char *) NULL, 0, local, (char *) NULL, - (char *) NULL); - } - - 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); -} - - -static int -rlog_proc (argc, argv, xwhere, mwhere, mfile, shorten, local, mname, msg) - int argc; - char **argv; - char *xwhere; - char *mwhere; - char *mfile; - int shorten; - int local; - char *mname; - char *msg; -{ - /* Begin section which is identical to patch_proc--should this - be abstracted out somehow? */ - char *myargv[2]; - int err = 0; - int which; - char *repository; - char *where; - - if (is_rlog) - { - repository = xmalloc (strlen (current_parsed_root->directory) - + strlen (argv[0]) - + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2); - (void)sprintf (repository, "%s/%s", - current_parsed_root->directory, argv[0]); - where = xmalloc (strlen (argv[0]) - + (mfile == NULL ? 0 : strlen (mfile) + 1) - + 1); - (void) strcpy (where, argv[0]); - - /* If mfile isn't null, we need to set up to do only part of theu - * module. - */ - if (mfile != NULL) - { - char *cp; - char *path; - - /* If the portion of the module is a path, put the dir part on - * repos. - */ - if ((cp = strrchr (mfile, '/')) != NULL) - { - *cp = '\0'; - (void)strcat (repository, "/"); - (void)strcat (repository, mfile); - (void)strcat (where, "/"); - (void)strcat (where, mfile); - mfile = cp + 1; - } - - /* take care of the rest */ - path = xmalloc (strlen (repository) + strlen (mfile) + 5); - (void)sprintf (path, "%s/%s", repository, mfile); - if (isdir (path)) - { - /* directory means repository gets the dir tacked on */ - (void)strcpy (repository, path); - (void)strcat (where, "/"); - (void)strcat (where, mfile); - } - else - { - myargv[0] = argv[0]; - myargv[1] = mfile; - argc = 2; - argv = myargv; - } - free (path); - } - - /* cd to the starting repository */ - if (CVS_CHDIR (repository) < 0) - { - error (0, errno, "cannot chdir to %s", repository); - free (repository); - free (where); - return 1; - } - /* End section which is identical to patch_proc. */ - - which = W_REPOS | W_ATTIC; - } - else - { - repository = NULL; - where = NULL; - which = W_LOCAL | W_REPOS | W_ATTIC; - } - - err = start_recursion (log_fileproc, (FILESDONEPROC) NULL, log_dirproc, - (DIRLEAVEPROC) NULL, (void *) &log_data, - argc - 1, argv + 1, local, which, 0, CVS_LOCK_READ, - where, 1, repository); - - if (!(which & W_LOCAL)) free (repository); - if (where) free (where); - - return err; -} - - - -/* - * Parse a revision list specification. - */ -static struct option_revlist * -log_parse_revlist (argstring) - const char *argstring; -{ - 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) - 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. */ - orig_copy = copy = xstrdup (argstring); - while (copy != NULL) - { - char *comma; - struct option_revlist *r; - - comma = strchr (copy, ','); - if (comma != NULL) - *comma++ = '\0'; - - r = (struct option_revlist *) xmalloc (sizeof *r); - r->next = NULL; - r->first = copy; - r->branchhead = 0; - r->last = strchr (copy, ':'); - if (r->last != NULL) - { - *r->last++ = '\0'; - r->inclusive = (*r->last != ':'); - if (!r->inclusive) - r->last++; - } - else - { - r->last = r->first; - r->inclusive = 1; - 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; -} - -/* - * Parse a date specification. - */ -static void -log_parse_date (log_data, argstring) - struct log_data *log_data; - const char *argstring; -{ - char *orig_copy, *copy; - - /* 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. */ - orig_copy = copy = xstrdup (argstring); - while (copy != NULL) - { - struct datelist *nd, **pd; - char *cpend, *cp, *ds, *de; - - nd = (struct datelist *) xmalloc (sizeof *nd); - - cpend = strchr (copy, ';'); - if (cpend != NULL) - *cpend++ = '\0'; - - pd = &log_data->datelist; - nd->inclusive = 0; - - if ((cp = strchr (copy, '>')) != NULL) - { - *cp++ = '\0'; - if (*cp == '=') - { - ++cp; - nd->inclusive = 1; - } - ds = cp; - de = copy; - } - else if ((cp = strchr (copy, '<')) != NULL) - { - *cp++ = '\0'; - if (*cp == '=') - { - ++cp; - nd->inclusive = 1; - } - ds = copy; - de = cp; - } - else - { - ds = NULL; - de = copy; - pd = &log_data->singledatelist; - } - - if (ds == NULL) - nd->start = NULL; - else if (*ds != '\0') - nd->start = Make_Date (ds); - else - { - /* 1970 was the beginning of time, as far as get_date and - Make_Date are concerned. FIXME: That is true only if time_t - is a POSIX-style time and there is nothing in ANSI that - mandates that. It would be cleaner to set a flag saying - whether or not there is a start date. */ - nd->start = Make_Date ("1/1/1970 UTC"); - } - - if (*de != '\0') - nd->end = Make_Date (de); - else - { - /* We want to set the end date to some time sufficiently far - in the future to pick up all revisions that have been - created since the specified date and the time `cvs log' - completes. FIXME: The date in question only makes sense - if time_t is a POSIX-style time and it is 32 bits - and signed. We should instead be setting a flag saying - whether or not there is an end date. Note that using - something like "next week" would break the testsuite (and, - perhaps less importantly, loses if the clock is set grossly - wrong). */ - nd->end = Make_Date ("2038-01-01"); - } - - nd->next = *pd; - *pd = nd; - - copy = cpend; - } - - free (orig_copy); -} - -/* - * Parse a comma separated list of items, and add each one to *PLIST. - */ -static void -log_parse_list (plist, argstring) - List **plist; - const char *argstring; -{ - while (1) - { - Node *p; - char *cp; - - p = getnode (); - - cp = strchr (argstring, ','); - if (cp == NULL) - p->key = xstrdup (argstring); - else - { - size_t len; - - len = cp - argstring; - p->key = xmalloc (len + 1); - strncpy (p->key, argstring, len); - p->key[len] = '\0'; - } - - if (*plist == NULL) - *plist = getlist (); - if (addnode (*plist, p) != 0) - freenode (p); - - if (cp == NULL) - break; - - argstring = cp + 1; - } -} - -static int printlock_proc PROTO ((Node *, void *)); - -static int -printlock_proc (lock, foo) - Node *lock; - void *foo; -{ - cvs_output ("\n\t", 2); - cvs_output (lock->data, 0); - cvs_output (": ", 2); - cvs_output (lock->key, 0); - return 0; -} - - - -/* - * Do an rlog on a file - */ -static int -log_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - struct log_data *log_data = (struct log_data *) callerdat; - Node *p; - char *baserev; - int selrev = -1; - RCSNode *rcsfile; - char buf[50]; - struct revlist *revlist = NULL; - struct log_data_and_rcs log_data_and_rcs; - - rcsfile = finfo->rcs; - p = findnode (finfo->entries, finfo->file); - if (p != NULL) - { - Entnode *e = p->data; - baserev = e->version; - if (baserev[0] == '-') ++baserev; - } - else - baserev = NULL; - - if (rcsfile == NULL) - { - /* no rcs file. What *do* we know about this file? */ - if (baserev != NULL) - { - if (baserev[0] == '0' && baserev[1] == '\0') - { - if (!really_quiet) - error (0, 0, "%s has been added, but not committed", - finfo->file); - return 0; - } - } - - if (!really_quiet) - error (0, 0, "nothing known about %s", finfo->file); - - return 1; - } - - if (log_data->sup_header || !log_data->nameonly) - { - - /* We will need all the information in the RCS file. */ - RCS_fully_parse (rcsfile); - - /* Turn any symbolic revisions in the revision list into numeric - revisions. */ - revlist = log_expand_revlist (rcsfile, baserev, log_data->revlist, - log_data->default_branch); - if (log_data->sup_header - || (!log_data->header && !log_data->long_header)) - { - log_data_and_rcs.log_data = log_data; - log_data_and_rcs.revlist = revlist; - log_data_and_rcs.rcs = rcsfile; - - /* If any single dates were specified, we need to identify the - revisions they select. Each one selects the single - revision, which is otherwise selected, of that date or - earlier. The log_fix_singledate routine will fill in the - start date for each specific revision. */ - if (log_data->singledatelist != NULL) - walklist (rcsfile->versions, log_fix_singledate, - (void *)&log_data_and_rcs); - - selrev = walklist (rcsfile->versions, log_count_print, - (void *)&log_data_and_rcs); - if (log_data->sup_header && selrev == 0) - { - log_free_revlist (revlist); - return 0; - } - } - - } - - if (log_data->nameonly) - { - cvs_output (rcsfile->path, 0); - cvs_output ("\n", 1); - log_free_revlist (revlist); - return 0; - } - - /* The output here is intended to be exactly compatible with the - output of rlog. I'm not sure whether this code should be here - or in rcs.c; I put it here because it is specific to the log - function, even though it uses information gathered by the - functions in rcs.c. */ - - cvs_output ("\n", 1); - - cvs_output ("RCS file: ", 0); - cvs_output (rcsfile->path, 0); - - if (!is_rlog) - { - cvs_output ("\nWorking file: ", 0); - if (finfo->update_dir[0] != '\0') - { - cvs_output (finfo->update_dir, 0); - cvs_output ("/", 0); - } - cvs_output (finfo->file, 0); - } - - cvs_output ("\nhead:", 0); - if (rcsfile->head != NULL) - { - cvs_output (" ", 1); - cvs_output (rcsfile->head, 0); - } - - cvs_output ("\nbranch:", 0); - if (rcsfile->branch != NULL) - { - cvs_output (" ", 1); - cvs_output (rcsfile->branch, 0); - } - - cvs_output ("\nlocks:", 0); - if (rcsfile->strict_locks) - cvs_output (" strict", 0); - walklist (RCS_getlocks (rcsfile), printlock_proc, NULL); - - cvs_output ("\naccess list:", 0); - if (rcsfile->access != NULL) - { - const char *cp; - - cp = rcsfile->access; - while (*cp != '\0') - { - const char *cp2; - - cvs_output ("\n\t", 2); - cp2 = cp; - while (!isspace ((unsigned char) *cp2) && *cp2 != '\0') - ++cp2; - cvs_output (cp, cp2 - cp); - cp = cp2; - while (isspace ((unsigned char) *cp) && *cp != '\0') - ++cp; - } - } - - if (!log_data->notags) - { - List *syms; - - cvs_output ("\nsymbolic names:", 0); - syms = RCS_symbols (rcsfile); - walklist (syms, log_symbol, NULL); - } - - cvs_output ("\nkeyword substitution: ", 0); - if (rcsfile->expand == NULL) - cvs_output ("kv", 2); - else - cvs_output (rcsfile->expand, 0); - - cvs_output ("\ntotal revisions: ", 0); - sprintf (buf, "%d", walklist (rcsfile->versions, log_count, NULL)); - cvs_output (buf, 0); - - if (selrev >= 0) - { - cvs_output (";\tselected revisions: ", 0); - sprintf (buf, "%d", selrev); - cvs_output (buf, 0); - } - - cvs_output ("\n", 1); - - if (!log_data->header || log_data->long_header) - { - cvs_output ("description:\n", 0); - if (rcsfile->desc != NULL) - cvs_output (rcsfile->desc, 0); - } - - if (!log_data->header && ! log_data->long_header && rcsfile->head != NULL) - { - p = findnode (rcsfile->versions, rcsfile->head); - if (p == NULL) - error (1, 0, "can not find head revision in `%s'", - finfo->fullname); - while (p != NULL) - { - RCSVers *vers = p->data; - - log_version (log_data, revlist, rcsfile, vers, 1); - if (vers->next == NULL) - p = NULL; - else - { - p = findnode (rcsfile->versions, vers->next); - if (p == NULL) - error (1, 0, "can not find next revision `%s' in `%s'", - vers->next, finfo->fullname); - } - } - - log_tree (log_data, revlist, rcsfile, rcsfile->head); - } - - cvs_output("\ -=============================================================================\n", - 0); - - /* Free up the new revlist and restore the old one. */ - log_free_revlist (revlist); - - /* If singledatelist is not NULL, free up the start dates we added - to it. */ - if (log_data->singledatelist != NULL) - { - struct datelist *d; - - for (d = log_data->singledatelist; d != NULL; d = d->next) - { - if (d->start != NULL) - free (d->start); - d->start = NULL; - } - } - - return 0; -} - - - -/* - * Fix up a revision list in order to compare it against versions. - * Expand any symbolic revisions. - */ -static struct revlist * -log_expand_revlist (rcs, baserev, revlist, default_branch) - RCSNode *rcs; - char *baserev; - struct option_revlist *revlist; - int default_branch; -{ - struct option_revlist *r; - struct revlist *ret, **pr; - - ret = NULL; - pr = &ret; - for (r = revlist; r != NULL; r = r->next) - { - struct revlist *nr; - - nr = (struct revlist *) xmalloc (sizeof *nr); - nr->inclusive = r->inclusive; - - if (r->first == NULL && r->last == NULL) - { - /* If both first and last are NULL, it means that we want - just the head of the default branch, which is RCS_head. */ - nr->first = RCS_head (rcs); - if (!nr->first) - { - if (!really_quiet) - error (0, 0, "No head revision in archive `%s'.", - rcs->path); - nr->last = NULL; - nr->fields = 0; - } - else - { - nr->last = xstrdup (nr->first); - nr->fields = numdots (nr->first) + 1; - } - } - else if (r->branchhead) - { - char *branch; - - assert (r->first != NULL); - - /* Print just the head of the branch. */ - if (isdigit ((unsigned char) r->first[0])) - nr->first = RCS_getbranch (rcs, r->first, 1); - else - { - branch = RCS_whatbranch (rcs, r->first); - if (branch == NULL) - nr->first = NULL; - else - { - nr->first = RCS_getbranch (rcs, branch, 1); - free (branch); - } - } - if (!nr->first) - { - if (!really_quiet) - error (0, 0, "warning: no branch `%s' in `%s'", - r->first, rcs->path); - nr->last = NULL; - nr->fields = 0; - } - else - { - nr->last = xstrdup (nr->first); - nr->fields = numdots (nr->first) + 1; - } - } - else - { - if (r->first == NULL || isdigit ((unsigned char) r->first[0])) - nr->first = xstrdup (r->first); - else - { - if (baserev && strcmp (r->first, TAG_BASE) == 0) - nr->first = xstrdup (baserev); - else if (RCS_nodeisbranch (rcs, r->first)) - nr->first = RCS_whatbranch (rcs, r->first); - else - nr->first = RCS_gettag (rcs, r->first, 1, (int *) NULL); - if (nr->first == NULL && !really_quiet) - { - error (0, 0, "warning: no revision `%s' in `%s'", - r->first, rcs->path); - } - } - - if (r->last == r->first || (r->last != NULL && r->first != NULL && - strcmp (r->last, r->first) == 0)) - nr->last = xstrdup (nr->first); - else if (r->last == NULL || isdigit ((unsigned char) r->last[0])) - nr->last = xstrdup (r->last); - else - { - if (baserev && strcmp (r->last, TAG_BASE) == 0) - nr->last = xstrdup (baserev); - else if (RCS_nodeisbranch (rcs, r->last)) - nr->last = RCS_whatbranch (rcs, r->last); - else - nr->last = RCS_gettag (rcs, r->last, 1, (int *) NULL); - if (nr->last == NULL && !really_quiet) - { - error (0, 0, "warning: no revision `%s' in `%s'", - r->last, rcs->path); - } - } - - /* Process the revision numbers the same way that rlog - does. This code is a bit cryptic for my tastes, but - keeping the same implementation as rlog ensures a - certain degree of compatibility. */ - if (r->first == NULL && nr->last != NULL) - { - nr->fields = numdots (nr->last) + 1; - if (nr->fields < 2) - nr->first = xstrdup (".0"); - else - { - char *cp; - - nr->first = xstrdup (nr->last); - cp = strrchr (nr->first, '.'); - assert (cp); - strcpy (cp + 1, "0"); - } - } - else if (r->last == NULL && nr->first != NULL) - { - nr->fields = numdots (nr->first) + 1; - nr->last = xstrdup (nr->first); - if (nr->fields < 2) - nr->last[0] = '\0'; - else - { - char *cp; - - cp = strrchr (nr->last, '.'); - assert (cp); - *cp = '\0'; - } - } - else if (nr->first == NULL || nr->last == NULL) - nr->fields = 0; - else if (strcmp (nr->first, nr->last) == 0) - nr->fields = numdots (nr->last) + 1; - else - { - int ord; - int dots1 = numdots (nr->first); - int dots2 = numdots (nr->last); - if (dots1 > dots2 || (dots1 == dots2 && - version_compare (nr->first, nr->last, dots1 + 1) > 0)) - { - char *tmp = nr->first; - nr->first = nr->last; - nr->last = tmp; - nr->fields = dots2 + 1; - dots2 = dots1; - dots1 = nr->fields - 1; - } - else - nr->fields = dots1 + 1; - dots1 += (nr->fields & 1); - ord = version_compare (nr->first, nr->last, dots1); - if (ord > 0 || (nr->fields > 2 && ord < 0)) - { - error (0, 0, - "invalid branch or revision pair %s:%s in `%s'", - r->first, r->last, rcs->path); - free (nr->first); - nr->first = NULL; - free (nr->last); - nr->last = NULL; - nr->fields = 0; - } - else - { - if (nr->fields <= dots2 && (nr->fields & 1)) - { - char *p = xmalloc (strlen (nr->first) + 3); - strcpy (p, nr->first); - strcat (p, ".0"); - free (nr->first); - nr->first = p; - ++nr->fields; - } - while (nr->fields <= dots2) - { - char *p; - int i; - - nr->next = NULL; - *pr = nr; - nr = (struct revlist *) xmalloc (sizeof *nr); - nr->inclusive = 1; - nr->first = xstrdup ((*pr)->last); - nr->last = xstrdup ((*pr)->last); - nr->fields = (*pr)->fields; - p = (*pr)->last; - for (i = 0; i < nr->fields; i++) - p = strchr (p, '.') + 1; - p[-1] = '\0'; - p = strchr (nr->first + (p - (*pr)->last), '.'); - if (p != NULL) - { - *++p = '0'; - *++p = '\0'; - nr->fields += 2; - } - else - ++nr->fields; - pr = &(*pr)->next; - } - } - } - } - - nr->next = NULL; - *pr = nr; - pr = &nr->next; - } - - /* If the default branch was requested, add a revlist entry for - it. This is how rlog handles this option. */ - if (default_branch - && (rcs->head != NULL || rcs->branch != NULL)) - { - struct revlist *nr; - - nr = (struct revlist *) xmalloc (sizeof *nr); - if (rcs->branch != NULL) - nr->first = xstrdup (rcs->branch); - else - { - char *cp; - - nr->first = xstrdup (rcs->head); - assert (nr->first); - cp = strrchr (nr->first, '.'); - assert (cp); - *cp = '\0'; - } - nr->last = xstrdup (nr->first); - nr->fields = numdots (nr->first) + 1; - nr->inclusive = 1; - - nr->next = NULL; - *pr = nr; - } - - return ret; -} - -/* - * Free a revlist created by log_expand_revlist. - */ -static void -log_free_revlist (revlist) - struct revlist *revlist; -{ - struct revlist *r; - - r = revlist; - while (r != NULL) - { - struct revlist *next; - - if (r->first != NULL) - free (r->first); - if (r->last != NULL) - free (r->last); - next = r->next; - free (r); - r = next; - } -} - -/* - * Return nonzero if a revision should be printed, based on the - * options provided. - */ -static int -log_version_requested (log_data, revlist, rcs, vnode) - struct log_data *log_data; - struct revlist *revlist; - RCSNode *rcs; - RCSVers *vnode; -{ - /* Handle the list of states from the -s option. */ - if (log_data->statelist != NULL - && findnode (log_data->statelist, vnode->state) == NULL) - { - return 0; - } - - /* Handle the list of authors from the -w option. */ - if (log_data->authorlist != NULL) - { - if (vnode->author != NULL - && findnode (log_data->authorlist, vnode->author) == NULL) - { - return 0; - } - } - - /* rlog considers all the -d options together when it decides - whether to print a revision, so we must be compatible. */ - if (log_data->datelist != NULL || log_data->singledatelist != NULL) - { - struct datelist *d; - - for (d = log_data->datelist; d != NULL; d = d->next) - { - int cmp; - - cmp = RCS_datecmp (vnode->date, d->start); - if (cmp > 0 || (cmp == 0 && d->inclusive)) - { - cmp = RCS_datecmp (vnode->date, d->end); - if (cmp < 0 || (cmp == 0 && d->inclusive)) - break; - } - } - - if (d == NULL) - { - /* Look through the list of specific dates. We want to - select the revision with the exact date found in the - start field. The commit code ensures that it is - impossible to check in multiple revisions of a single - file in a single second, so checking the date this way - should never select more than one revision. */ - for (d = log_data->singledatelist; d != NULL; d = d->next) - { - if (d->start != NULL - && RCS_datecmp (vnode->date, d->start) == 0) - { - break; - } - } - - if (d == NULL) - return 0; - } - } - - /* If the -r or -b options were used, REVLIST will be non NULL, - and we print the union of the specified revisions. */ - if (revlist != NULL) - { - char *v; - int vfields; - struct revlist *r; - - /* This code is taken from rlog. */ - v = vnode->version; - vfields = numdots (v) + 1; - for (r = revlist; r != NULL; r = r->next) - { - if (vfields == r->fields + (r->fields & 1) && - (r->inclusive ? version_compare (v, r->first, r->fields) >= 0 : - version_compare (v, r->first, r->fields) > 0) - && version_compare (v, r->last, r->fields) <= 0) - { - return 1; - } - } - - /* If we get here, then the -b and/or the -r option was used, - but did not match this revision, so we reject it. */ - - return 0; - } - - /* By default, we print all revisions. */ - return 1; -} - - - -/* - * Output a single symbol. This is called via walklist. - */ -/*ARGSUSED*/ -static int -log_symbol (p, closure) - Node *p; - void *closure; -{ - cvs_output ("\n\t", 2); - cvs_output (p->key, 0); - cvs_output (": ", 2); - cvs_output (p->data, 0); - return 0; -} - - - -/* - * Count the number of entries on a list. This is called via walklist. - */ -/*ARGSUSED*/ -static int -log_count (p, closure) - Node *p; - void *closure; -{ - return 1; -} - - - -/* - * Sort out a single date specification by narrowing down the date - * until we find the specific selected revision. - */ -static int -log_fix_singledate (p, closure) - Node *p; - void *closure; -{ - struct log_data_and_rcs *data = (struct log_data_and_rcs *) closure; - Node *pv; - RCSVers *vnode; - struct datelist *holdsingle, *holddate; - int requested; - - pv = findnode (data->rcs->versions, p->key); - if (pv == NULL) - error (1, 0, "missing version `%s' in RCS file `%s'", - p->key, data->rcs->path); - vnode = pv->data; - - /* We are only interested if this revision passes any other tests. - Temporarily clear log_data->singledatelist to avoid confusing - log_version_requested. We also clear log_data->datelist, - because rlog considers all the -d options together. We don't - want to reject a revision because it does not match a date pair - if we are going to select it on the basis of the singledate. */ - holdsingle = data->log_data->singledatelist; - data->log_data->singledatelist = NULL; - holddate = data->log_data->datelist; - data->log_data->datelist = NULL; - requested = log_version_requested (data->log_data, data->revlist, - data->rcs, vnode); - data->log_data->singledatelist = holdsingle; - data->log_data->datelist = holddate; - - if (requested) - { - struct datelist *d; - - /* For each single date, if this revision is before the - specified date, but is closer than the previously selected - revision, select it instead. */ - for (d = data->log_data->singledatelist; d != NULL; d = d->next) - { - if (RCS_datecmp (vnode->date, d->end) <= 0 - && (d->start == NULL - || RCS_datecmp (vnode->date, d->start) > 0)) - { - if (d->start != NULL) - free (d->start); - d->start = xstrdup (vnode->date); - } - } - } - - return 0; -} - - - -/* - * Count the number of revisions we are going to print. - */ -static int -log_count_print (p, closure) - Node *p; - void *closure; -{ - struct log_data_and_rcs *data = (struct log_data_and_rcs *) closure; - Node *pv; - - pv = findnode (data->rcs->versions, p->key); - if (pv == NULL) - error (1, 0, "missing version `%s' in RCS file `%s'", - p->key, data->rcs->path); - if (log_version_requested (data->log_data, data->revlist, data->rcs, - pv->data)) - return 1; - else - return 0; -} - -/* - * Print the list of changes, not including the trunk, in reverse - * order for each branch. - */ -static void -log_tree (log_data, revlist, rcs, ver) - struct log_data *log_data; - struct revlist *revlist; - RCSNode *rcs; - const char *ver; -{ - Node *p; - RCSVers *vnode; - - p = findnode (rcs->versions, ver); - if (p == NULL) - error (1, 0, "missing version `%s' in RCS file `%s'", - ver, rcs->path); - vnode = p->data; - if (vnode->next != NULL) - log_tree (log_data, revlist, rcs, vnode->next); - if (vnode->branches != NULL) - { - Node *head, *branch; - - /* We need to do the branches in reverse order. This breaks - the List abstraction, but so does most of the branch - manipulation in rcs.c. */ - head = vnode->branches->list; - for (branch = head->prev; branch != head; branch = branch->prev) - { - log_abranch (log_data, revlist, rcs, branch->key); - log_tree (log_data, revlist, rcs, branch->key); - } - } -} - -/* - * Log the changes for a branch, in reverse order. - */ -static void -log_abranch (log_data, revlist, rcs, ver) - struct log_data *log_data; - struct revlist *revlist; - RCSNode *rcs; - const char *ver; -{ - Node *p; - RCSVers *vnode; - - p = findnode (rcs->versions, ver); - if (p == NULL) - error (1, 0, "missing version `%s' in RCS file `%s'", - ver, rcs->path); - vnode = p->data; - if (vnode->next != NULL) - log_abranch (log_data, revlist, rcs, vnode->next); - log_version (log_data, revlist, rcs, vnode, 0); -} - -/* - * Print the log output for a single version. - */ -static void -log_version (log_data, revlist, rcs, ver, trunk) - struct log_data *log_data; - struct revlist *revlist; - RCSNode *rcs; - RCSVers *ver; - int trunk; -{ - Node *p; - int year, mon, mday, hour, min, sec; - char buf[100]; - Node *padd, *pdel; - - if (! log_version_requested (log_data, revlist, rcs, ver)) - return; - - cvs_output ("----------------------------\nrevision ", 0); - cvs_output (ver->version, 0); - - p = findnode (RCS_getlocks (rcs), ver->version); - if (p != NULL) - { - cvs_output ("\tlocked by: ", 0); - cvs_output (p->data, 0); - cvs_output (";", 1); - } - - cvs_output ("\ndate: ", 0); - (void) sscanf (ver->date, SDATEFORM, &year, &mon, &mday, &hour, &min, - &sec); - if (year < 1900) - year += 1900; - sprintf (buf, "%04d%c%02d%c%02d %02d:%02d:%02d", - year, datesep, mon, datesep, mday, hour, min, sec); - cvs_output (buf, 0); - - cvs_output ("; author: ", 0); - cvs_output (ver->author, 0); - - cvs_output ("; state: ", 0); - cvs_output (ver->state, 0); - cvs_output (";", 1); - - if (! trunk) - { - padd = findnode (ver->other, ";add"); - pdel = findnode (ver->other, ";delete"); - } - else if (ver->next == NULL) - { - padd = NULL; - pdel = NULL; - } - else - { - Node *nextp; - RCSVers *nextver; - - nextp = findnode (rcs->versions, ver->next); - if (nextp == NULL) - error (1, 0, "missing version `%s' in `%s'", ver->next, - rcs->path); - nextver = nextp->data; - pdel = findnode (nextver->other, ";add"); - padd = findnode (nextver->other, ";delete"); - } - - if (padd != NULL) - { - assert (pdel); - cvs_output (" lines: +", 0); - cvs_output (padd->data, 0); - cvs_output (" -", 2); - cvs_output (pdel->data, 0); - } - - if (ver->branches != NULL) - { - cvs_output ("\nbranches:", 0); - walklist (ver->branches, log_branch, (void *) NULL); - } - - cvs_output ("\n", 1); - - p = findnode (ver->other, "log"); - /* The p->date == NULL case is the normal one for an empty log - message (rcs-14 in sanity.sh). I don't think the case where - p->data is "" can happen (getrcskey in rcs.c checks for an - empty string and set the value to NULL in that case). My guess - would be the p == NULL case would mean an RCS file which was - missing the "log" keyword (which is illegal according to - rcsfile.5). */ - if (p == NULL || p->data == NULL || *(char *)p->data == '\0') - cvs_output ("*** empty log message ***\n", 0); - else - { - /* FIXME: Technically, the log message could contain a null - byte. */ - cvs_output (p->data, 0); - if (((char *)p->data)[strlen (p->data) - 1] != '\n') - cvs_output ("\n", 1); - } -} - -/* - * Output a branch version. This is called via walklist. - */ -/*ARGSUSED*/ -static int -log_branch (p, closure) - Node *p; - void *closure; -{ - cvs_output (" ", 2); - if ((numdots (p->key) & 1) == 0) - cvs_output (p->key, 0); - else - { - char *f, *cp; - - f = xstrdup (p->key); - cp = strrchr (f, '.'); - *cp = '\0'; - cvs_output (f, 0); - free (f); - } - cvs_output (";", 1); - return 0; -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -log_dirproc (callerdat, dir, repository, update_dir, entries) - void *callerdat; - const char *dir; - const char *repository; - const char *update_dir; - List *entries; -{ - if (!isdir (dir)) - return (R_SKIP_ALL); - - if (!quiet) - error (0, 0, "Logging %s", update_dir); - return (R_PROCESS); -} - -/* - * Compare versions. This is taken from RCS compartial. - */ -static int -version_compare (v1, v2, len) - const char *v1; - const char *v2; - int len; -{ - while (1) - { - int d1, d2, r; - - if (*v1 == '\0') - return 1; - if (*v2 == '\0') - return -1; - - while (*v1 == '0') - ++v1; - for (d1 = 0; isdigit ((unsigned char) v1[d1]); ++d1) - ; - - while (*v2 == '0') - ++v2; - for (d2 = 0; isdigit ((unsigned char) v2[d2]); ++d2) - ; - - if (d1 != d2) - return d1 < d2 ? -1 : 1; - - r = memcmp (v1, v2, d1); - if (r != 0) - return r; - - --len; - if (len == 0) - return 0; - - v1 += d1; - v2 += d1; - - if (*v1 == '.') - ++v1; - if (*v2 == '.') - ++v2; - } -} diff --git a/contrib/cvs/src/login.c b/contrib/cvs/src/login.c deleted file mode 100644 index 1d20c97..0000000 --- a/contrib/cvs/src/login.c +++ /dev/null @@ -1,686 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (c) 1995, Cyclic Software, Bloomington, IN, USA - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with CVS. - * - * Allow user to log in for an authenticating server. - */ - -#include "cvs.h" -#include "getline.h" - -#ifdef AUTH_CLIENT_SUPPORT /* This covers the rest of the file. */ - -/* 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 - _CRAY, since Cray is perhaps the only system on which our own - declaration won't work (some Crays declare the 2#$@% thing as - varadic, believe it or not). On Cray, getpass will be declared - in either stdlib.h or unistd.h. */ - -#ifndef CVS_PASSWORD_FILE -#define CVS_PASSWORD_FILE ".cvspass" -#endif - -/* If non-NULL, get_cvs_password() will just return this. */ -static char *cvs_password = NULL; - -static char *construct_cvspass_filename PROTO ((void)); - -/* The return value will need to be freed. */ -static char * -construct_cvspass_filename () -{ - char *homedir; - char *passfile; - - /* Environment should override file. */ - if ((passfile = getenv ("CVS_PASSFILE")) != NULL) - return xstrdup (passfile); - - /* Construct absolute pathname to user's password file. */ - /* todo: does this work under OS/2 ? */ - homedir = get_homedir (); - if (! homedir) - { - /* FIXME? This message confuses a lot of users, at least - on Win95 (which doesn't set HOMEDRIVE and HOMEPATH like - NT does). I suppose the answer for Win95 is to store the - passwords in the registry or something (??). And .cvsrc - and such too? Wonder what WinCVS does (about .cvsrc, the - right thing for a GUI is to just store the password in - memory only)... */ - error (1, 0, "could not find out home directory"); - return (char *) NULL; - } - - passfile = strcat_filename_onto_homedir (homedir, CVS_PASSWORD_FILE); - - /* Safety first and last, Scouts. */ - if (isfile (passfile)) - /* xchmod() is too polite. */ - chmod (passfile, 0600); - - return passfile; -} - - - -/* - * static char * - * password_entry_parseline ( - * const char *cvsroot_canonical, - * const unsigned char warn, - * const int linenumber, - * char *linebuf - * ); - * - * Internal function used by password_entry_operation. Parse a single line - * from a ~/.cvsroot password file and return a pointer to the password if the - * line refers to the same cvsroot as cvsroot_canonical - * - * INPUTS - * cvsroot_canonical the root we are looking for - * warn Boolean: print warnings for invalid lines? - * linenumber the line number for error messages - * linebuf the current line - * - * RETURNS - * NULL if the line doesn't match - * char *password as a pointer into linebuf - * - * NOTES - * This function temporarily alters linebuf, so it isn't thread safe when - * called on the same linebuf - */ -static char * -password_entry_parseline (cvsroot_canonical, warn, linenumber, linebuf) - const char *cvsroot_canonical; - const unsigned char warn; - const int linenumber; - char *linebuf; -{ - char *password = NULL; - char *p; - - /* look for '^/' */ - if (*linebuf == '/') - { - /* Yes: slurp '^/\d+\D' and parse the rest of the line according to version number */ - char *q; - unsigned long int entry_version = 0; - - if (isspace(*(linebuf + 1))) - { - /* special case since strtoul ignores leading white space */ - q = linebuf + 1; - } - else - { - entry_version = strtoul (linebuf + 1, &q, 10); - if (q != linebuf + 1) - /* assume a delimiting seperator */ - q++; - } - - switch (entry_version) - { - case 1: - /* this means the same normalize_cvsroot we are using was - * used to create this entry. strcmp is good enough for - * us. - */ - p = strchr (q, ' '); - if (p == NULL) - { - if (warn && !really_quiet) - error (0, 0, "warning: skipping invalid entry in password file at line %d", - linenumber); - } - else - { - *p = '\0'; - if (strcmp (cvsroot_canonical, q) == 0) - password = p + 1; - *p = ' '; - } - break; - case ULONG_MAX: - if (warn && !really_quiet) - { - error (0, errno, "warning: unable to convert version number in password file at line %d", - linenumber); - error (0, 0, "skipping entry"); - } - break; - case 0: - if (warn && !really_quiet) - error (0, 0, "warning: skipping entry with invalid version string in password file at line %d", - linenumber); - break; - default: - if (warn && !really_quiet) - error (0, 0, "warning: skipping entry with unknown version (%lu) in password file at line %d", - entry_version, linenumber); - break; - } - } - else - { - /* No: assume: - * - * ^cvsroot Aencoded_password$ - * - * as header comment specifies and parse accordingly - */ - cvsroot_t *tmp_root; - char *tmp_root_canonical; - - p = strchr (linebuf, ' '); - if (p == NULL) - { - if (warn && !really_quiet) - error (0, 0, "warning: skipping invalid entry in password file at line %d", linenumber); - return NULL;; - } - - *p = '\0'; - if ((tmp_root = parse_cvsroot (linebuf)) == NULL) - { - if (warn && !really_quiet) - error (0, 0, "warning: skipping invalid entry in password file at line %d", linenumber); - *p = ' '; - return NULL; - } - *p = ' '; - tmp_root_canonical = normalize_cvsroot (tmp_root); - if (strcmp (cvsroot_canonical, tmp_root_canonical) == 0) - password = p + 1; - - free (tmp_root_canonical); - free_cvsroot_t (tmp_root); - } - - return password; -} - - - -/* - * static char * - * password_entry_operation ( - * password_entry_operation_t operation, - * cvsroot_t *root, - * char *newpassword - * ); - * - * Search the password file and depending on the value of operation: - * - * Mode Action - * password_entry_lookup Return the password - * password_entry_delete Delete the entry from the file, if it - * exists. - * password_entry_add Replace the line with the new one, else - * append it. - * - * Because the user might be accessing multiple repositories, with - * different passwords for each one, the format of ~/.cvspass is: - * - * [user@]host:[port]/path Aencoded_password - * [user@]host:[port]/path Aencoded_password - * ... - * - * New entries are always of the form: - * - * /1 user@host:port/path Aencoded_password - * - * but the old format is supported for backwards compatibility. - * The entry version string wasn't strictly necessary, but it avoids the - * overhead of parsing some entries since we know it is already in canonical - * form and allows room for expansion later, say, if we want to allow spaces - * and/or other characters to be escaped in the string. Also, the new entries - * would have been ignored by old versions of CVS anyhow since those versions - * didn't know how to parse a port number. - * - * The "A" before "encoded_password" is a literal capital A. It's a - * version number indicating which form of scrambling we're doing on - * the password -- someday we might provide something more secure than - * the trivial encoding we do now, and when that day comes, it would - * be nice to remain backward-compatible. - * - * Like .netrc, the file's permissions are the only thing preventing - * it from being read by others. Unlike .netrc, we will not be - * fascist about it, at most issuing a warning, and never refusing to - * work. - * - * INPUTS - * operation operation to perform - * root cvsroot_t to look up - * newpassword prescrambled new password, for password_entry_add_mode - * - * RETURNS - * -1 if password_entry_lookup_mode not specified - * NULL on failed lookup - * pointer to a copy of the password string otherwise, which the caller is - * responsible for disposing of - */ - -typedef enum password_entry_operation_e { - password_entry_lookup, - password_entry_delete, - password_entry_add -} password_entry_operation_t; - -static char * -password_entry_operation (operation, root, newpassword) - password_entry_operation_t operation; - cvsroot_t *root; - char *newpassword; -{ - char *passfile; - FILE *fp; - char *cvsroot_canonical = NULL; - char *password = NULL; - int line_length; - long line = -1; - char *linebuf = NULL; - size_t linebuf_len; - char *p; - int save_errno = 0; - - if (root->method != pserver_method) - { - error (0, 0, "\ -internal error: can only call password_entry_operation with pserver method"); - error (1, 0, "CVSROOT: %s", root->original); - } - - cvsroot_canonical = normalize_cvsroot (root); - - /* Yes, the method below reads the user's password file twice when we have - * to delete an entry. It's inefficient, but we're not talking about a gig of - * data here. - */ - - passfile = construct_cvspass_filename (); - fp = CVS_FOPEN (passfile, "r"); - if (fp == NULL) - { - error (0, errno, "warning: failed to open %s for reading", passfile); - goto process; - } - - /* Check each line to see if we have this entry already. */ - line = 0; - while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0) - { - line++; - password = password_entry_parseline (cvsroot_canonical, 1, line, - linebuf); - if (password != NULL) - /* this is it! break out and deal with linebuf */ - break; - } - if (line_length < 0 && !feof (fp)) - { - error (0, errno, "cannot read %s", passfile); - goto error_exit; - } - if (fclose (fp) < 0) - /* not fatal, unless it cascades */ - error (0, errno, "cannot close %s", passfile); - fp = NULL; - - /* Utter, total, raving paranoia, I know. */ - chmod (passfile, 0600); - - /* a copy to return or keep around so we can reuse linebuf */ - if (password != NULL) - { - /* chomp the EOL */ - p = strchr (password, '\n'); - if (p != NULL) - *p = '\0'; - password = xstrdup (password); - } - -process: - - /* might as well return now */ - if (operation == password_entry_lookup) - goto out; - - /* same here */ - if (operation == password_entry_delete && password == NULL) - { - error (0, 0, "Entry not found."); - goto out; - } - - /* okay, file errors can simply be fatal from now on since we don't do - * anything else if we're in lookup mode - */ - - /* copy the file with the entry deleted unless we're in add - * mode and the line we found contains the same password we're supposed to - * add - */ - if (!noexec && password != NULL && (operation == password_entry_delete - || (operation == password_entry_add - && strcmp (password, newpassword)))) - { - long found_at = line; - char *tmp_name; - FILE *tmp_fp; - - /* open the original file again */ - fp = CVS_FOPEN (passfile, "r"); - if (fp == NULL) - error (1, errno, "failed to open %s for reading", passfile); - - /* create and open a temp file */ - if ((tmp_fp = cvs_temp_file (&tmp_name)) == NULL) - error (1, errno, "unable to open temp file %s", - tmp_name ? tmp_name : "(null)"); - - line = 0; - while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0) - { - line++; - if (line < found_at - || (line != found_at - && !password_entry_parseline (cvsroot_canonical, 0, line, - linebuf))) - { - if (fprintf (tmp_fp, "%s", linebuf) == EOF) - { - /* try and clean up anyhow */ - error (0, errno, "fatal error: cannot write %s", tmp_name); - if (fclose (tmp_fp) == EOF) - error (0, errno, "cannot close %s", tmp_name); - /* call CVS_UNLINK instead of unlink_file since the file - * got created in noexec mode - */ - if (CVS_UNLINK (tmp_name) < 0) - error (0, errno, "cannot remove %s", tmp_name); - /* but quit so we don't remove all the entries from a - * user's password file accidentally - */ - error (1, 0, "exiting"); - } - } - } - if (line_length < 0 && !feof (fp)) - { - error (0, errno, "cannot read %s", passfile); - goto error_exit; - } - if (fclose (fp) < 0) - /* not fatal, unless it cascades */ - error (0, errno, "cannot close %s", passfile); - if (fclose (tmp_fp) < 0) - /* not fatal, unless it cascades */ - /* FIXME - does copy_file return correct results if the file wasn't - * closed? should this be fatal? - */ - error (0, errno, "cannot close %s", tmp_name); - - /* FIXME: rename_file would make more sense (e.g. almost - * always faster). - * - * I don't think so, unless we change the way rename_file works to - * attempt a cp/rm sequence when rename fails since rename doesn't - * work across file systems and it isn't uncommon to have /tmp - * on its own partition. - * - * For that matter, it's probably not uncommon to have a home - * directory on an NFS mount. - */ - copy_file (tmp_name, passfile); - if (CVS_UNLINK (tmp_name) < 0) - error (0, errno, "cannot remove %s", tmp_name); - free (tmp_name); - } - - /* in add mode, if we didn't find an entry or found an entry with a - * different password, append the new line - */ - if (!noexec && operation == password_entry_add - && (password == NULL || strcmp (password, newpassword))) - { - if ((fp = CVS_FOPEN (passfile, "a")) == NULL) - error (1, errno, "could not open %s for writing", passfile); - - if (fprintf (fp, "/1 %s %s\n", cvsroot_canonical, newpassword) == EOF) - error (1, errno, "cannot write %s", passfile); - if (fclose (fp) < 0) - error (1, errno, "cannot close %s", passfile); - } - - /* Utter, total, raving paranoia, I know. */ - chmod (passfile, 0600); - - if (password) - { - free (password); - password = NULL; - } - if (linebuf) - free (linebuf); - -out: - free (cvsroot_canonical); - free (passfile); - return password; - -error_exit: - /* just exit when we're not in lookup mode */ - if (operation != password_entry_lookup) - error (1, 0, "fatal error: exiting"); - /* clean up and exit in lookup mode so we can try a login with a NULL - * password anyhow in case that's what we would have found - */ - save_errno = errno; - if (fp != NULL) - { - /* Utter, total, raving paranoia, I know. */ - chmod (passfile, 0600); - if(fclose (fp) < 0) - error (0, errno, "cannot close %s", passfile); - } - if (linebuf) - free (linebuf); - if (cvsroot_canonical) - free (cvsroot_canonical); - free (passfile); - errno = save_errno; - return NULL; -} - - - -/* Prompt for a password, and store it in the file "CVS/.cvspass". - */ - -static const char *const login_usage[] = -{ - "Usage: %s %s\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -int -login (argc, argv) - int argc; - char **argv; -{ - char *typed_password; - char *cvsroot_canonical; - - if (argc < 0) - usage (login_usage); - - if (current_parsed_root->method != pserver_method) - { - error (0, 0, "can only use `login' command with the 'pserver' method"); - error (1, 0, "CVSROOT: %s", current_parsed_root->original); - } - - cvsroot_canonical = normalize_cvsroot(current_parsed_root); - printf ("Logging in to %s\n", cvsroot_canonical); - fflush (stdout); - - if (current_parsed_root->password) - { - typed_password = scramble (current_parsed_root->password); - } - else - { - char *tmp; - tmp = getpass ("CVS password: "); - /* Must deal with a NULL return value here. I haven't managed to - * disconnect the CVS process from the tty and force a NULL return - * in sanity.sh, but the Linux version of getpass is documented - * to return NULL when it can't open /dev/tty... - */ - if (!tmp) error (1, errno, "login: Failed to read password."); - typed_password = scramble (tmp); - memset (tmp, 0, strlen (tmp)); - } - - /* Force get_cvs_password() to use this one (when the client - * confirms the new password with the server), instead of - * consulting the file. We make a new copy because cvs_password - * will get zeroed by connect_to_server(). */ - cvs_password = xstrdup (typed_password); - - connect_to_pserver (current_parsed_root, NULL, NULL, 1, 0); - - password_entry_operation (password_entry_add, current_parsed_root, - typed_password); - - free_cvs_password (typed_password); - free (cvsroot_canonical); - - return 0; -} - - - -/* Free the password returned by get_cvs_password() and also free the - * saved cvs_password if they are different pointers. Be paranoid - * about the in-memory copy of the password and overwrite it with zero - * bytes before doing the free(). - */ -void -free_cvs_password (char *password) -{ - if (password && password != cvs_password) - { - memset (password, 0, strlen (password)); - free (password); - } - - if (cvs_password) - { - memset (cvs_password, 0, strlen (cvs_password)); - free (cvs_password); - cvs_password = NULL; - } -} - -/* Returns the _scrambled_ password in freshly allocated memory. The server - * must descramble before hashing and comparing. If password file not found, - * or password not found in the file, just return NULL. - */ -char * -get_cvs_password () -{ - if (current_parsed_root->password) - return scramble (current_parsed_root->password); - - /* If someone (i.e., login()) is calling connect_to_pserver() out of - context, then assume they have supplied the correct, scrambled - password. */ - if (cvs_password) - return xstrdup (cvs_password); - - if (getenv ("CVS_PASSWORD") != NULL) - { - /* In previous versions of CVS one could specify a password in - * CVS_PASSWORD. This is a bad idea, because in BSD variants - * of unix anyone can see the environment variable with 'ps'. - * But for users who were using that feature we want to at - * least let them know what is going on. After printing this - * warning, we should fall through to the regular error where - * we tell them to run "cvs login" (unless they already ran - * it, of course). - */ - error (0, 0, "CVS_PASSWORD is no longer supported; ignored"); - } - - if (current_parsed_root->method != pserver_method) - { - error (0, 0, "can only call get_cvs_password with pserver method"); - error (1, 0, "CVSROOT: %s", current_parsed_root->original); - } - - return password_entry_operation (password_entry_lookup, - current_parsed_root, NULL); -} - - - -static const char *const logout_usage[] = -{ - "Usage: %s %s\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -/* Remove any entry for the CVSRoot repository found in .cvspass. */ -int -logout (argc, argv) - int argc; - char **argv; -{ - char *cvsroot_canonical; - - if (argc < 0) - usage (logout_usage); - - if (current_parsed_root->method != pserver_method) - { - error (0, 0, "can only use pserver method with `logout' command"); - error (1, 0, "CVSROOT: %s", current_parsed_root->original); - } - - /* Hmm. Do we want a variant of this command which deletes _all_ - the entries from the current .cvspass? Might be easier to - remember than "rm ~/.cvspass" but then again if people are - mucking with HOME (common in Win95 as the system doesn't set - it), then this variant of "cvs logout" might give a false sense - of security, in that it wouldn't delete entries from any - .cvspass files but the current one. */ - - if (!quiet) - { - cvsroot_canonical = normalize_cvsroot(current_parsed_root); - printf ("Logging out of %s\n", cvsroot_canonical); - fflush (stdout); - free (cvsroot_canonical); - } - - password_entry_operation (password_entry_delete, current_parsed_root, NULL); - - return 0; -} - -#endif /* AUTH_CLIENT_SUPPORT from beginning of file. */ diff --git a/contrib/cvs/src/logmsg.c b/contrib/cvs/src/logmsg.c deleted file mode 100644 index 6878aaf..0000000 --- a/contrib/cvs/src/logmsg.c +++ /dev/null @@ -1,988 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * $FreeBSD$ - */ - -#include <assert.h> - -#include "cvs.h" -#include "getline.h" - -static int find_type PROTO((Node * p, void *closure)); -static int fmt_proc PROTO((Node * p, void *closure)); -static int logfile_write PROTO((const char *repository, const char *filter, - const char *message, FILE * logfp, - List * changes)); -static int rcsinfo_proc PROTO((const char *repository, const char *template)); -static int title_proc PROTO((Node * p, void *closure)); -static int update_logfile_proc PROTO((const char *repository, - const char *filter)); -static void setup_tmpfile PROTO((FILE * xfp, char *xprefix, List * changes)); -static int editinfo_proc PROTO((const char *repository, const char *template)); -static int verifymsg_proc PROTO((const char *repository, const char *script)); - -static FILE *fp; -static char *str_list; -static char *str_list_format; /* The format for str_list's contents. */ -static char *editinfo_editor; -static char *verifymsg_script; -static Ctype type; - -/* - * Should the logmsg be re-read during the do_verify phase? - * RereadLogAfterVerify=no|stat|yes - * LOGMSG_REREAD_NEVER - never re-read the logmsg - * LOGMSG_REREAD_STAT - re-read the logmsg only if it has changed - * LOGMSG_REREAD_ALWAYS - always re-read the logmsg - */ -int RereadLogAfterVerify = LOGMSG_REREAD_ALWAYS; - -/* - * Puts a standard header on the output which is either being prepared for an - * editor session, or being sent to a logfile program. The modified, added, - * and removed files are included (if any) and formatted to look pretty. */ -static char *prefix; -static int col; -static char *tag; -static void -setup_tmpfile (xfp, xprefix, changes) - FILE *xfp; - char *xprefix; - List *changes; -{ - /* set up statics */ - fp = xfp; - prefix = xprefix; - - type = T_MODIFIED; - if (walklist (changes, find_type, NULL) != 0) - { - (void) fprintf (fp, "%sModified Files:\n", prefix); - col = 0; - (void) walklist (changes, fmt_proc, NULL); - (void) fprintf (fp, "\n"); - if (tag != NULL) - { - free (tag); - tag = NULL; - } - } - type = T_ADDED; - if (walklist (changes, find_type, NULL) != 0) - { - (void) fprintf (fp, "%sAdded Files:\n", prefix); - col = 0; - (void) walklist (changes, fmt_proc, NULL); - (void) fprintf (fp, "\n"); - if (tag != NULL) - { - free (tag); - tag = NULL; - } - } - type = T_REMOVED; - if (walklist (changes, find_type, NULL) != 0) - { - (void) fprintf (fp, "%sRemoved Files:\n", prefix); - col = 0; - (void) walklist (changes, fmt_proc, NULL); - (void) fprintf (fp, "\n"); - if (tag != NULL) - { - free (tag); - tag = NULL; - } - } -} - -/* - * Looks for nodes of a specified type and returns 1 if found - */ -static int -find_type (p, closure) - Node *p; - void *closure; -{ - struct logfile_info *li = p->data; - - if (li->type == type) - return (1); - else - return (0); -} - -/* - * Breaks the files list into reasonable sized lines to avoid line wrap... - * all in the name of pretty output. It only works on nodes whose types - * match the one we're looking for - */ -static int -fmt_proc (p, closure) - Node *p; - void *closure; -{ - struct logfile_info *li; - - li = p->data; - if (li->type == type) - { - if (li->tag == NULL - ? tag != NULL - : tag == NULL || strcmp (tag, li->tag) != 0) - { - if (col > 0) - (void) fprintf (fp, "\n"); - (void) fputs (prefix, fp); - col = strlen (prefix); - while (col < 6) - { - (void) fprintf (fp, " "); - ++col; - } - - if (li->tag == NULL) - (void) fprintf (fp, "No tag"); - else - (void) fprintf (fp, "Tag: %s", li->tag); - - if (tag != NULL) - free (tag); - tag = xstrdup (li->tag); - - /* Force a new line. */ - col = 70; - } - - if (col == 0) - { - (void) fprintf (fp, "%s\t", prefix); - col = 8; - } - else if (col > 8 && (col + (int) strlen (p->key)) > 70) - { - (void) fprintf (fp, "\n%s\t", prefix); - col = 8; - } - (void) fprintf (fp, "%s ", p->key); - col += strlen (p->key) + 1; - } - return (0); -} - -/* - * Builds a temporary file using setup_tmpfile() and invokes the user's - * editor on the file. The header garbage in the resultant file is then - * stripped and the log message is stored in the "message" argument. - * - * If REPOSITORY is non-NULL, process rcsinfo for that repository; if it - * is NULL, use the CVSADM_TEMPLATE file instead. REPOSITORY should be - * NULL when running in client mode. - */ -void -do_editor (dir, messagep, repository, changes) - const char *dir; - char **messagep; - const char *repository; - List *changes; -{ - static int reuse_log_message = 0; - char *line; - int line_length; - size_t line_chars_allocated; - char *fname; - struct stat pre_stbuf, post_stbuf; - int retcode = 0; - - assert (!current_parsed_root->isremote != !repository); - - if (noexec || reuse_log_message) - return; - - /* Abort creation of temp file if no editor is defined */ - if (strcmp (Editor, "") == 0 && !editinfo_editor) - error(1, 0, "no editor defined, must use -e or -m"); - - /* Create a temporary file */ - /* FIXME - It's possible we should be relying on cvs_temp_file to open - * the file here - we get race conditions otherwise. - */ - fname = cvs_temp_name (); - again: - if ((fp = CVS_FOPEN (fname, "w+")) == NULL) - error (1, 0, "cannot create temporary file %s", fname); - - if (*messagep) - { - (void) fputs (*messagep, fp); - - if ((*messagep)[0] == '\0' || - (*messagep)[strlen (*messagep) - 1] != '\n') - (void) fprintf (fp, "\n"); - } - else - (void) fprintf (fp, "\n"); - - if (repository != NULL) - /* tack templates on if necessary */ - (void) Parse_Info (CVSROOTADM_RCSINFO, repository, rcsinfo_proc, 1); - else - { - FILE *tfp; - char buf[1024]; - size_t n; - size_t nwrite; - - /* Why "b"? */ - tfp = CVS_FOPEN (CVSADM_TEMPLATE, "rb"); - if (tfp == NULL) - { - if (!existence_error (errno)) - error (1, errno, "cannot read %s", CVSADM_TEMPLATE); - } - else - { - while (!feof (tfp)) - { - char *p = buf; - n = fread (buf, 1, sizeof buf, tfp); - nwrite = n; - while (nwrite > 0) - { - n = fwrite (p, 1, nwrite, fp); - nwrite -= n; - p += n; - } - if (ferror (tfp)) - error (1, errno, "cannot read %s", CVSADM_TEMPLATE); - } - if (fclose (tfp) < 0) - error (0, errno, "cannot close %s", CVSADM_TEMPLATE); - } - } - - (void) fprintf (fp, - "%s----------------------------------------------------------------------\n", - CVSEDITPREFIX); - (void) fprintf (fp, - "%sEnter Log. Lines beginning with `%.*s' are removed automatically\n%s\n", - CVSEDITPREFIX, CVSEDITPREFIXLEN, CVSEDITPREFIX, - CVSEDITPREFIX); - if (dir != NULL && *dir) - (void) fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX, - dir, CVSEDITPREFIX); - if (changes != NULL) - setup_tmpfile (fp, CVSEDITPREFIX, changes); - (void) fprintf (fp, - "%s----------------------------------------------------------------------\n", - CVSEDITPREFIX); - - /* finish off the temp file */ - if (fclose (fp) == EOF) - error (1, errno, "%s", fname); - if ( CVS_STAT (fname, &pre_stbuf) == -1) - pre_stbuf.st_mtime = 0; - - if (editinfo_editor) - free (editinfo_editor); - editinfo_editor = (char *) NULL; - if (!current_parsed_root->isremote && repository != NULL) - (void) Parse_Info (CVSROOTADM_EDITINFO, repository, editinfo_proc, 0); - - /* run the editor */ - run_setup (editinfo_editor ? editinfo_editor : Editor); - run_arg (fname); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, - RUN_NORMAL | RUN_SIGIGNORE)) != 0) - error (editinfo_editor ? 1 : 0, retcode == -1 ? errno : 0, - editinfo_editor ? "Logfile verification failed" : - "warning: editor session failed"); - - /* put the entire message back into the *messagep variable */ - - fp = open_file (fname, "r"); - - if (*messagep) - free (*messagep); - - if ( CVS_STAT (fname, &post_stbuf) != 0) - error (1, errno, "cannot find size of temp file %s", fname); - - if (post_stbuf.st_size == 0) - *messagep = NULL; - else - { - /* On NT, we might read less than st_size bytes, but we won't - read more. So this works. */ - *messagep = (char *) xmalloc (post_stbuf.st_size + 1); - (*messagep)[0] = '\0'; - } - - line = NULL; - line_chars_allocated = 0; - - if (*messagep) - { - size_t message_len = post_stbuf.st_size + 1; - size_t offset = 0; - while (1) - { - line_length = getline (&line, &line_chars_allocated, fp); - if (line_length == -1) - { - if (ferror (fp)) - error (0, errno, "warning: cannot read %s", fname); - break; - } - if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0) - continue; - 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) - error (0, errno, "warning: cannot close %s", fname); - - /* canonicalize emply messages */ - if (*messagep != NULL && - (**messagep == '\0' || strcmp (*messagep, "\n") == 0)) - { - free (*messagep); - *messagep = NULL; - } - - if (pre_stbuf.st_mtime == post_stbuf.st_mtime || *messagep == NULL) - { - for (;;) - { - (void) printf ("\nLog message unchanged or not specified\n"); - (void) printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n"); - (void) printf ("Action: (continue) "); - (void) fflush (stdout); - line_length = getline (&line, &line_chars_allocated, stdin); - if (line_length < 0) - { - error (0, errno, "cannot read from stdin"); - if (unlink_file (fname) < 0) - error (0, errno, - "warning: cannot remove temp file %s", fname); - error (1, 0, "aborting"); - } - else if (line_length == 0 - || *line == '\n' || *line == 'c' || *line == 'C') - break; - if (*line == 'a' || *line == 'A') - { - if (unlink_file (fname) < 0) - error (0, errno, "warning: cannot remove temp file %s", fname); - error (1, 0, "aborted by user"); - } - if (*line == 'e' || *line == 'E') - goto again; - if (*line == '!') - { - reuse_log_message = 1; - break; - } - (void) printf ("Unknown input\n"); - } - } - if (line) - free (line); - if (unlink_file (fname) < 0) - error (0, errno, "warning: cannot remove temp file %s", fname); - free (fname); -} - -/* Runs the user-defined verification script as part of the commit or import - process. This verification is meant to be run whether or not the user - included the -m atribute. unlike the do_editor function, this is - independant of the running of an editor for getting a message. - */ -void -do_verify (messagep, repository) - char **messagep; - const char *repository; -{ - FILE *fp; - char *fname; - int retcode = 0; - - struct stat pre_stbuf, post_stbuf; - - if (current_parsed_root->isremote) - /* The verification will happen on the server. */ - return; - - /* FIXME? Do we really want to skip this on noexec? What do we do - for the other administrative files? */ - if (noexec || repository == NULL) - return; - - /* Get the name of the verification script to run */ - - if (Parse_Info (CVSROOTADM_VERIFYMSG, repository, verifymsg_proc, 0) > 0) - error (1, 0, "Message verification failed"); - - if (!verifymsg_script) - return; - - /* open a temporary file, write the message to the - temp file, and close the file. */ - - if ((fp = cvs_temp_file (&fname)) == NULL) - error (1, errno, "cannot create temporary file %s", - fname ? fname : "(null)"); - - if (*messagep != NULL) - fputs (*messagep, fp); - if (*messagep == NULL || - (*messagep)[0] == '\0' || - (*messagep)[strlen (*messagep) - 1] != '\n') - putc ('\n', fp); - if (fclose (fp) == EOF) - error (1, errno, "%s", fname); - - if (RereadLogAfterVerify == LOGMSG_REREAD_STAT) - { - /* Remember the status of the temp file for later */ - if ( CVS_STAT (fname, &pre_stbuf) != 0 ) - error (1, errno, "cannot stat temp file %s", fname); - - /* - * See if we need to sleep before running the verification - * script to avoid time-stamp races. - */ - sleep_past (pre_stbuf.st_mtime); - } - - run_setup (verifymsg_script); - run_arg (fname); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, - RUN_NORMAL | RUN_SIGIGNORE)) != 0) - { - /* Since following error() exits, delete the temp file now. */ - if (unlink_file (fname) < 0) - error (0, errno, "cannot remove %s", fname); - - error (1, retcode == -1 ? errno : 0, - "Message verification failed"); - } - - /* Get the mod time and size of the possibly new log message - * in always and stat modes. - */ - if (RereadLogAfterVerify == LOGMSG_REREAD_ALWAYS || - RereadLogAfterVerify == LOGMSG_REREAD_STAT) - { - if ( CVS_STAT (fname, &post_stbuf) != 0 ) - error (1, errno, "cannot find size of temp file %s", fname); - } - - /* And reread the log message in `always' mode or in `stat' mode when it's - * changed - */ - if (RereadLogAfterVerify == LOGMSG_REREAD_ALWAYS || - (RereadLogAfterVerify == LOGMSG_REREAD_STAT && - (pre_stbuf.st_mtime != post_stbuf.st_mtime || - pre_stbuf.st_size != post_stbuf.st_size))) - { - /* put the entire message back into the *messagep variable */ - - if (*messagep) free (*messagep); - - if (post_stbuf.st_size == 0) - *messagep = NULL; - else - { - char *line = NULL; - int line_length; - size_t line_chars_allocated = 0; - char *p; - - if ( (fp = open_file (fname, "r")) == NULL ) - error (1, errno, "cannot open temporary file %s", fname); - - /* On NT, we might read less than st_size bytes, - but we won't read more. So this works. */ - p = *messagep = (char *) xmalloc (post_stbuf.st_size + 1); - *messagep[0] = '\0'; - - while (1) - { - line_length = getline (&line, - &line_chars_allocated, - fp); - if (line_length == -1) - { - if (ferror (fp)) - /* Fail in this case because otherwise we will have no - * log message - */ - error (1, errno, "cannot read %s", fname); - break; - } - if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0) - continue; - (void) strcpy (p, line); - p += line_length; - } - if (line) free (line); - if (fclose (fp) < 0) - error (0, errno, "warning: cannot close %s", fname); - } - } - - /* Delete the temp file */ - - if (unlink_file (fname) < 0) - error (0, errno, "cannot remove %s", fname); - free (fname); - free (verifymsg_script); - verifymsg_script = NULL; -} - -/* - * callback proc for Parse_Info for rcsinfo templates this routine basically - * copies the matching template onto the end of the tempfile we are setting - * up - */ -/* ARGSUSED */ -static int -rcsinfo_proc (repository, template) - const char *repository; - const char *template; -{ - static char *last_template; - FILE *tfp; - - /* nothing to do if the last one included is the same as this one */ - if (last_template && strcmp (last_template, template) == 0) - return (0); - if (last_template) - free (last_template); - last_template = xstrdup (template); - - if ((tfp = CVS_FOPEN (template, "r")) != NULL) - { - char *line = NULL; - size_t line_chars_allocated = 0; - - while (getline (&line, &line_chars_allocated, tfp) >= 0) - (void) fputs (line, fp); - if (ferror (tfp)) - error (0, errno, "warning: cannot read %s", template); - if (fclose (tfp) < 0) - error (0, errno, "warning: cannot close %s", template); - if (line) - free (line); - return (0); - } - else - { - error (0, errno, "Couldn't open rcsinfo template file %s", template); - return (1); - } -} - -/* - * Uses setup_tmpfile() to pass the updated message on directly to any - * logfile programs that have a regular expression match for the checked in - * directory in the source repository. The log information is fed into the - * specified program as standard input. - */ -static FILE *logfp; -static const char *message; -static List *changes; - -void -Update_Logfile (repository, xmessage, xlogfp, xchanges) - const char *repository; - const char *xmessage; - FILE *xlogfp; - List *xchanges; -{ - /* nothing to do if the list is empty */ - if (xchanges == NULL || xchanges->list->next == xchanges->list) - return; - - /* set up static vars for update_logfile_proc */ - message = xmessage; - logfp = xlogfp; - changes = xchanges; - - /* call Parse_Info to do the actual logfile updates */ - (void) Parse_Info (CVSROOTADM_LOGINFO, repository, update_logfile_proc, 1); -} - - - -/* - * callback proc to actually do the logfile write from Update_Logfile - */ -static int -update_logfile_proc (repository, filter) - const char *repository; - const char *filter; -{ - return logfile_write (repository, filter, message, logfp, changes); -} - - - -/* - * concatenate each filename/version onto str_list - */ -static int -title_proc (p, closure) - Node *p; - void *closure; -{ - char *c; - struct logfile_info *li = p->data; - - if (li->type == type) - { - /* Until we decide on the correct logging solution when we add - directories or perform imports, T_TITLE nodes will only - tack on the name provided, regardless of the format string. - You can verify that this assumption is safe by checking the - code in add.c (add_directory) and import.c (import). */ - - str_list = xrealloc (str_list, strlen (str_list) + 5); - (void) strcat (str_list, " "); - - if (li->type == T_TITLE) - { - str_list = xrealloc (str_list, - strlen (str_list) + strlen (p->key) + 5); - (void) strcat (str_list, p->key); - } - else - { - /* All other nodes use the format string. */ - - for (c = str_list_format; *c != '\0'; c++) - { - switch (*c) - { - case 's': - str_list = - xrealloc (str_list, - strlen (str_list) + strlen (p->key) + 5); - (void) strcat (str_list, p->key); - break; - case 'V': - str_list = - xrealloc (str_list, - (strlen (str_list) - + (li->rev_old ? strlen (li->rev_old) : 0) - + 10) - ); - (void) strcat (str_list, (li->rev_old - ? li->rev_old : "NONE")); - break; - case 'v': - str_list = - xrealloc (str_list, - (strlen (str_list) - + (li->rev_new ? strlen (li->rev_new) : 0) - + 10) - ); - (void) strcat (str_list, (li->rev_new - ? li->rev_new : "NONE")); - break; - /* All other characters, we insert an empty field (but - we do put in the comma separating it from other - fields). This way if future CVS versions add formatting - characters, one can write a loginfo file which at least - won't blow up on an old CVS. */ - /* Note that people who have to deal with spaces in file - and directory names are using space to get a known - delimiter for the directory name, so it's probably - not a good idea to ever define that as a formatting - character. */ - } - if (*(c + 1) != '\0') - { - str_list = xrealloc (str_list, strlen (str_list) + 5); - (void) strcat (str_list, ","); - } - } - } - } - return (0); -} - -/* - * Writes some stuff to the logfile "filter" and returns the status of the - * filter program. - */ -static int -logfile_write (repository, filter, message, logfp, changes) - const char *repository; - const char *filter; - const char *message; - FILE *logfp; - List *changes; -{ - FILE *pipefp; - char *prog; - char *cp; - int c; - int pipestatus; - char *fmt_percent; /* the location of the percent sign - that starts the format string. */ - - assert (repository); - - /* The user may specify a format string as part of the filter. - Originally, `%s' was the only valid string. The string that - was substituted for it was: - - <repository-name> <file1> <file2> <file3> ... - - Each file was either a new directory/import (T_TITLE), or a - added (T_ADDED), modified (T_MODIFIED), or removed (T_REMOVED) - file. - - It is desirable to preserve that behavior so lots of commitlog - scripts won't die when they get this new code. At the same - time, we'd like to pass other information about the files (like - version numbers, statuses, or checkin times). - - The solution is to allow a format string that allows us to - specify those other pieces of information. The format string - will be composed of `%' followed by a single format character, - or followed by a set of format characters surrounded by `{' and - `}' as separators. The format characters are: - - s = file name - V = old version number (pre-checkin) - v = new version number (post-checkin) - - For example, valid format strings are: - - %{} - %s - %{s} - %{sVv} - - There's no reason that more items couldn't be added (like - modification date or file status [added, modified, updated, - etc.]) -- the code modifications would be minimal (logmsg.c - (title_proc) and commit.c (check_fileproc)). - - The output will be a string of tokens separated by spaces. For - backwards compatibility, the the first token will be the - repository name. The rest of the tokens will be - comma-delimited lists of the information requested in the - format string. For example, if `/u/src/master' is the - repository, `%{sVv}' is the format string, and three files - (ChangeLog, Makefile, foo.c) were modified, the output might - be: - - /u/src/master ChangeLog,1.1,1.2 Makefile,1.3,1.4 foo.c,1.12,1.13 - - Why this duplicates the old behavior when the format string is - `%s' is left as an exercise for the reader. */ - - fmt_percent = strchr (filter, '%'); - if (fmt_percent) - { - int len; - const char *srepos; - char *fmt_begin, *fmt_end; /* beginning and end of the - format string specified in - filter. */ - char *fmt_continue; /* where the string continues - after the format string (we - might skip a '}') somewhere - in there... */ - - /* Grab the format string. */ - - if ((*(fmt_percent + 1) == ' ') || (*(fmt_percent + 1) == '\0')) - { - /* The percent stands alone. This is an error. We could - be treating ' ' like any other formatting character, but - using it as a formatting character seems like it would be - a mistake. */ - - /* Would be nice to also be giving the line number. */ - error (0, 0, "loginfo: '%%' not followed by formatting character"); - fmt_begin = fmt_percent + 1; - fmt_end = fmt_begin; - fmt_continue = fmt_begin; - } - else if (*(fmt_percent + 1) == '{') - { - /* The percent has a set of characters following it. */ - - fmt_begin = fmt_percent + 2; - fmt_end = strchr (fmt_begin, '}'); - if (fmt_end) - { - /* Skip over the '}' character. */ - - fmt_continue = fmt_end + 1; - } - else - { - /* There was no close brace -- assume that format - string continues to the end of the line. */ - - /* Would be nice to also be giving the line number. */ - error (0, 0, "loginfo: '}' missing"); - fmt_end = fmt_begin + strlen (fmt_begin); - fmt_continue = fmt_end; - } - } - else - { - /* The percent has a single character following it. FIXME: - %% should expand to a regular percent sign. */ - - fmt_begin = fmt_percent + 1; - fmt_end = fmt_begin + 1; - fmt_continue = fmt_end; - } - - len = fmt_end - fmt_begin; - str_list_format = xmalloc (len + 1); - strncpy (str_list_format, fmt_begin, len); - str_list_format[len] = '\0'; - - /* Allocate an initial chunk of memory. As we build up the string - we will realloc it. */ - if (!str_list) - str_list = xmalloc (1); - str_list[0] = '\0'; - - /* Add entries to the string. Don't bother looking for - entries if the format string is empty. */ - - if (str_list_format[0] != '\0') - { - type = T_TITLE; - (void) walklist (changes, title_proc, NULL); - type = T_ADDED; - (void) walklist (changes, title_proc, NULL); - type = T_MODIFIED; - (void) walklist (changes, title_proc, NULL); - type = T_REMOVED; - (void) walklist (changes, title_proc, NULL); - } - - free (str_list_format); - - /* Construct the final string. */ - - srepos = Short_Repository (repository); - - prog = cp = xmalloc ((fmt_percent - filter) + 2 * strlen (srepos) - + 2 * strlen (str_list) + strlen (fmt_continue) - + 10); - (void) memcpy (cp, filter, fmt_percent - filter); - cp += fmt_percent - filter; - *cp++ = '"'; - cp = shell_escape (cp, srepos); - cp = shell_escape (cp, str_list); - *cp++ = '"'; - (void) strcpy (cp, fmt_continue); - - /* To be nice, free up some memory. */ - - free (str_list); - str_list = (char *) NULL; - } - else - { - /* There's no format string. */ - prog = xstrdup (filter); - } - - if ((pipefp = run_popen (prog, "w")) == NULL) - { - if (!noexec) - error (0, 0, "cannot write entry to log filter: %s", prog); - free (prog); - return (1); - } - (void) fprintf (pipefp, "Update of %s\n", repository); - (void) fprintf (pipefp, "In directory %s:", hostname); - cp = xgetwd (); - if (cp == NULL) - fprintf (pipefp, "<cannot get working directory: %s>\n\n", - strerror (errno)); - else - { - fprintf (pipefp, "%s\n\n", cp); - free (cp); - } - - setup_tmpfile (pipefp, "", changes); - (void) fprintf (pipefp, "Log Message:\n%s\n", (message) ? message : ""); - if (logfp != (FILE *) 0) - { - (void) fprintf (pipefp, "Status:\n"); - rewind (logfp); - while ((c = getc (logfp)) != EOF) - (void) putc ((char) c, pipefp); - } - free (prog); - pipestatus = pclose (pipefp); - return ((pipestatus == -1) || (pipestatus == 127)) ? 1 : 0; -} - -/* - * We choose to use the *last* match within the editinfo file for this - * repository. This allows us to have a global editinfo program for the - * root of some hierarchy, for example, and different ones within different - * sub-directories of the root (like a special checker for changes made to - * the "src" directory versus changes made to the "doc" or "test" - * directories. - */ -/* ARGSUSED */ -static int -editinfo_proc(repository, editor) - const char *repository; - const char *editor; -{ - /* nothing to do if the last match is the same as this one */ - if (editinfo_editor && strcmp (editinfo_editor, editor) == 0) - return (0); - if (editinfo_editor) - free (editinfo_editor); - - editinfo_editor = xstrdup (editor); - return (0); -} - -/* This routine is calld by Parse_Info. it asigns the name of the - * message verification script to the global variable verify_script - */ -static int -verifymsg_proc (repository, script) - const char *repository; - const char *script; -{ - if (verifymsg_script && strcmp (verifymsg_script, script) == 0) - return (0); - if (verifymsg_script) - free (verifymsg_script); - verifymsg_script = xstrdup (script); - return (0); -} diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c deleted file mode 100644 index 332946a..0000000 --- a/contrib/cvs/src/main.c +++ /dev/null @@ -1,1240 +0,0 @@ -/* - * Copyright (C) 1986-2008 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2006 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License - * as specified in the README file that comes with the CVS source distribution. - * - * This is the main C driver for the CVS system. - * - * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing - * the shell-script CVS system that this is based on. - * - * $FreeBSD$ - */ - -#include <assert.h> -#include "cvs.h" -#include "prepend_args.h" - -#ifdef HAVE_WINSOCK_H -#include <winsock.h> -#else -extern int gethostname (); -#endif - -const char *program_name; -const char *program_path; -const char *cvs_cmd_name; - -/* I'd dynamically allocate this, but it seems like gethostname - requires a fixed size array. If I'm remembering the RFCs right, - 256 should be enough. */ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 256 -#endif - -char hostname[MAXHOSTNAMELEN]; - -int use_editor = 1; -int use_cvsrc = 1; -int cvswrite = !CVSREAD_DFLT; -int really_quiet = 0; -int quiet = 0; -int trace = 0; -int noexec = 0; -int readonlyfs = 0; -int require_real_user = 0; -int logoff = 0; - -/* - * Zero if compression isn't supported or requested; non-zero to indicate - * a compression level to request from gzip. - */ -int gzip_level; - -/* Set if we should be writing CVSADM directories at top level. At - least for now we'll make the default be off (the CVS 1.9, not CVS - 1.9.2, behavior). */ -int top_level_admin = 0; - -mode_t cvsumask = UMASK_DFLT; - -char *CurDir; - -/* - * Defaults, for the environment variables that are not set - */ -char *Tmpdir = TMPDIR_DFLT; -char *Editor = EDITOR_DFLT; - - -/* When our working directory contains subdirectories with different - values in CVS/Root files, we maintain a list of them. */ -List *root_directories = NULL; - -static const struct cmd -{ - char *fullname; /* Full name of the function (e.g. "commit") */ - - /* Synonyms for the command, nick1 and nick2. We supply them - mostly for two reasons: (1) CVS has always supported them, and - we need to maintain compatibility, (2) if there is a need for a - version which is shorter than the fullname, for ease in typing. - Synonyms have the disadvantage that people will see "new" and - then have to think about it, or look it up, to realize that is - the operation they know as "add". Also, this means that one - cannot create a command "cvs new" with a different meaning. So - new synonyms are probably best used sparingly, and where used - should be abbreviations of the fullname (preferably consisting - of the first 2 or 3 or so letters). - - One thing that some systems do is to recognize any unique - abbreviation, for example "annotat" "annota", etc., for - "annotate". The problem with this is that scripts and user - habits will expect a certain abbreviation to be unique, and in - a future release of CVS it may not be. So it is better to - accept only an explicit list of abbreviations and plan on - supporting them in the future as well as now. */ - - char *nick1; - char *nick2; - - int (*func) (); /* Function takes (argc, argv) arguments. */ - unsigned long attr; /* Attributes. */ -} cmds[] = - -{ - { "add", "ad", "new", add, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "admin", "adm", "rcs", admin, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "annotate", "ann", "blame", annotate, CVS_CMD_USES_WORK_DIR }, - { "checkout", "co", "get", checkout, 0 }, - { "commit", "ci", "com", commit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "diff", "di", "dif", diff, CVS_CMD_USES_WORK_DIR }, - { "edit", NULL, NULL, edit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "editors", NULL, NULL, editors, CVS_CMD_USES_WORK_DIR }, - { "export", "exp", "ex", checkout, CVS_CMD_USES_WORK_DIR }, - { "history", "hi", "his", history, CVS_CMD_USES_WORK_DIR }, - { "import", "im", "imp", import, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR | CVS_CMD_IGNORE_ADMROOT}, - { "init", NULL, NULL, init, CVS_CMD_MODIFIES_REPOSITORY }, -#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT) - { "kserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */ -#endif - { "log", "lo", NULL, cvslog, CVS_CMD_USES_WORK_DIR }, -#ifdef AUTH_CLIENT_SUPPORT - { "login", "logon", "lgn", login, 0 }, - { "logout", NULL, NULL, logout, 0 }, -#endif /* AUTH_CLIENT_SUPPORT */ -#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) - { "pserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */ -#endif - { "rannotate","rann", "ra", annotate, 0 }, - { "rdiff", "patch", "pa", patch, 0 }, - { "release", "re", "rel", release, 0 }, - { "remove", "rm", "delete", cvsremove, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "rlog", "rl", NULL, cvslog, 0 }, - { "rtag", "rt", "rfreeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY }, -#ifdef SERVER_SUPPORT - { "server", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, -#endif - { "status", "st", "stat", cvsstatus, CVS_CMD_USES_WORK_DIR }, - { "tag", "ta", "freeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "unedit", NULL, NULL, unedit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "update", "up", "upd", update, CVS_CMD_USES_WORK_DIR }, - { "version", "ve", "ver", version, 0 }, - { "watch", NULL, NULL, watch, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, - { "watchers", NULL, NULL, watchers, CVS_CMD_USES_WORK_DIR }, - { NULL, NULL, NULL, NULL, 0 }, -}; - -static const char *const usg[] = -{ - /* CVS usage messages never have followed the GNU convention of - putting metavariables in uppercase. I don't know whether that - is a good convention or not, but if it changes it would have to - change in all the usage messages. For now, they consistently - use lowercase, as far as I know. Punctuation is pretty funky, - though. Sometimes they use none, as here. Sometimes they use - single quotes (not the TeX-ish `' stuff), as in --help-options. - Sometimes they use double quotes, as in cvs -H add. - - Most (not all) of the usage messages seem to have periods at - the end of each line. I haven't tried to duplicate this style - in --help as it is a rather different format from the rest. */ - - "Usage: %s [cvs-options] command [command-options-and-arguments]\n", - " where cvs-options are -q, -n, etc.\n", - " (specify --help-options for a list of options)\n", - " where command is add, admin, etc.\n", - " (specify --help-commands for a list of commands\n", - " or --help-synonyms for a list of command synonyms)\n", - " where command-options-and-arguments depend on the specific command\n", - " (specify -H followed by a command name for command-specific help)\n", - " Specify --help to receive this message\n", - "\n", - - /* Some people think that a bug-reporting address should go here. IMHO, - the web sites are better because anything else is very likely to go - obsolete in the years between a release and when someone might be - reading this help. Besides, we could never adequately discuss - bug reporting in a concise enough way to put in a help message. */ - - /* I was going to put this at the top, but usage() wants the %s to - be in the first line. */ - "The Concurrent Versions System (CVS) is a tool for version control.\n", - /* I really don't think I want to try to define "version control" - in one line. I'm not sure one can get more concise than the - paragraph in ../cvs.spec without assuming the reader knows what - version control means. */ - - "For CVS updates and additional information, see\n", - " the CVS home page at http://cvs.nongnu.org/\n", - NULL, -}; - -static const char *const cmd_usage[] = -{ - "CVS commands are:\n", - " add Add a new file/directory to the repository\n", - " admin Administration front end for rcs\n", - " annotate Show last revision where each line was modified\n", - " checkout Checkout sources for editing\n", - " commit Check files into the repository\n", - " diff Show differences between revisions\n", - " edit Get ready to edit a watched file\n", - " editors See who is editing a watched file\n", - " export Export sources from CVS, similar to checkout\n", - " 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", -#endif /* AUTH_CLIENT_SUPPORT */ -#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) - " pserver Password server mode\n", -#endif - " rannotate Show last revision where each line of module was modified\n", - " 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", - " rlog Print out history information for a module\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", - " update Bring work tree in sync with repository\n", - " version Show current CVS version(s)\n", - " watch Set watches\n", - " watchers See who is watching a file\n", - "(Specify the --help option for a list of other help options)\n", - NULL, -}; - -static const char *const opt_usage[] = -{ - /* Omit -b because it is just for compatibility. */ - "CVS global options (specified before the command name) are:\n", - " -H Displays usage information for command.\n", - " -Q Cause CVS to be really quiet.\n", - " -q Cause CVS to be somewhat quiet.\n", - " -r Make checked-out files read-only.\n", - " -w Make checked-out files read-write (default).\n", - " -g Force group-write perms on checked-out files.\n", - " -n Do not execute anything that will change the disk.\n", - " -t Show trace of program execution -- try with -n.\n", - " -R Assume repository is read-only, such as CDROM\n", - " -v CVS version and copyright.\n", - " -T tmpdir Use 'tmpdir' for temporary files.\n", - " -e editor Use 'editor' for editing log information.\n", - " -d CVS_root Overrides $CVSROOT as the root of the CVS tree.\n", - " -f Do not use the ~/.cvsrc file.\n", -#ifdef CLIENT_SUPPORT - " -z # Use compression level '#' for net traffic.\n", -#ifdef ENCRYPTION - " -x Encrypt all net traffic.\n", -#endif - " -a Authenticate all net traffic.\n", -#endif - " -s VAR=VAL Set CVS user variable.\n", - "(Specify the --help option for a list of other help options)\n", - NULL -}; - - -static int -set_root_directory (p, ignored) - Node *p; - void *ignored; -{ - if (current_parsed_root == NULL && p->data != NULL) - { - current_parsed_root = p->data; - return 1; - } - return 0; -} - - -static const char * const* -cmd_synonyms () -{ - char ** synonyms; - char ** line; - const struct cmd *c = &cmds[0]; - /* Three more for title, "specify --help" line, and NULL. */ - int numcmds = 3; - - while (c->fullname != NULL) - { - numcmds++; - c++; - } - - synonyms = (char **) xmalloc(numcmds * sizeof(char *)); - line = synonyms; - *line++ = "CVS command synonyms are:\n"; - for (c = &cmds[0]; c->fullname != NULL; c++) - { - if (c->nick1 || c->nick2) - { - *line = xmalloc (strlen (c->fullname) - + (c->nick1 != NULL ? strlen (c->nick1) : 0) - + (c->nick2 != NULL ? strlen (c->nick2) : 0) - + 40); - sprintf(*line, " %-12s %s %s\n", c->fullname, - c->nick1 ? c->nick1 : "", - c->nick2 ? c->nick2 : ""); - line++; - } - } - *line++ = "(Specify the --help option for a list of other help options)\n"; - *line = NULL; - - return (const char * const*) synonyms; /* will never be freed */ -} - - -unsigned long int -lookup_command_attribute (cmd_name) - char *cmd_name; -{ - const struct cmd *cm; - - for (cm = cmds; cm->fullname; cm++) - { - if (strcmp (cmd_name, cm->fullname) == 0) - break; - } - if (!cm->fullname) - error (1, 0, "unknown command: %s", cmd_name); - return cm->attr; -} - - -static RETSIGTYPE -main_cleanup (sig) - int sig; -{ -#ifndef DONT_USE_SIGNALS - const char *name; - char temp[10]; - - switch (sig) - { -#ifdef SIGABRT - case SIGABRT: - name = "abort"; - break; -#endif -#ifdef SIGHUP - case SIGHUP: - name = "hangup"; - break; -#endif -#ifdef SIGINT - case SIGINT: - name = "interrupt"; - break; -#endif -#ifdef SIGQUIT - case SIGQUIT: - name = "quit"; - break; -#endif -#ifdef SIGPIPE - case SIGPIPE: - name = "broken pipe"; - break; -#endif -#ifdef SIGTERM - case SIGTERM: - name = "termination"; - break; -#endif - default: - /* This case should never be reached, because we list above all - the signals for which we actually establish a signal handler. */ - sprintf (temp, "%d", sig); - name = temp; - break; - } - - error (1, 0, "received %s signal", name); -#endif /* !DONT_USE_SIGNALS */ -} - -int -main (argc, argv) - int argc; - char **argv; -{ - cvsroot_t *CVSroot_parsed = NULL; - int cvsroot_update_env = 1; - char *cp, *end; - const struct cmd *cm; - int c, err = 0; - int tmpdir_update_env; - int free_Editor = 0; - int free_Tmpdir = 0; - - 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[] = "+QqgrwtnRvb:T:e:d:Hfz:s:xaU"; - static struct option long_options[] = - { - {"help", 0, NULL, 'H'}, - {"version", 0, NULL, 'v'}, - {"help-commands", 0, NULL, 1}, - {"help-synonyms", 0, NULL, 2}, - {"help-options", 0, NULL, 4}, - {"allow-root", required_argument, NULL, 3}, - {0, 0, 0, 0} - }; - /* `getopt_long' stores the option index here, but right now we - don't use it. */ - int option_index = 0; - -#ifdef SYSTEM_INITIALIZE - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_INITIALIZE (&argc, &argv); -#endif - -#ifdef HAVE_TZSET - /* On systems that have tzset (which is almost all the ones I know - of), it's a good idea to call it. */ - tzset (); -#endif - - /* - * Just save the last component of the path for error messages - */ - program_path = xstrdup (argv[0]); -#ifdef ARGV0_NOT_PROGRAM_NAME - /* On some systems, e.g. VMS, argv[0] is not the name of the command - which the user types to invoke the program. */ - program_name = "cvs"; -#else - program_name = last_component (argv[0]); -#endif - - /* - * Query the environment variables up-front, so that - * they can be overridden by command line arguments - */ - tmpdir_update_env = *Tmpdir; /* TMPDIR_DFLT must be set */ - if ((cp = getenv (TMPDIR_ENV)) != NULL) - { - Tmpdir = cp; - tmpdir_update_env = 0; /* it's already there */ - } - if ((cp = getenv (EDITOR1_ENV)) != NULL) - Editor = cp; - else if ((cp = getenv (EDITOR2_ENV)) != NULL) - Editor = cp; - else if ((cp = getenv (EDITOR3_ENV)) != NULL) - Editor = cp; - if (getenv (CVSREAD_ENV) != NULL) - cvswrite = 0; - if (getenv (CVSREADONLYFS_ENV) != NULL) { - readonlyfs = 1; - logoff = 1; - } - - prepend_default_options (getenv ("CVS_OPTIONS"), &argc, &argv); - - /* Set this to 0 to force getopt initialization. getopt() sets - this to 1 internally. */ - optind = 0; - - /* We have to parse the options twice because else there is no - chance to avoid reading the global options from ".cvsrc". Set - opterr to 0 for avoiding error messages about invalid options. - */ - opterr = 0; - - while ((c = getopt_long - (argc, argv, short_options, long_options, &option_index)) - != EOF) - { - if (c == 'f') - use_cvsrc = 0; - } - - /* - * Scan cvsrc file for global options. - */ - if (use_cvsrc) - read_cvsrc (&argc, &argv, "cvs"); - - optind = 0; - opterr = 1; - - while ((c = getopt_long - (argc, argv, short_options, long_options, &option_index)) - != EOF) - { - switch (c) - { - case 1: - /* --help-commands */ - usage (cmd_usage); - break; - case 2: - /* --help-synonyms */ - usage (cmd_synonyms()); - break; - case 4: - /* --help-options */ - usage (opt_usage); - break; - case 3: - /* --allow-root */ - root_allow_add (optarg); - break; - case 'Q': - really_quiet = 1; - /* FALL THROUGH */ - case 'q': - quiet = 1; - break; - case 'r': - cvswrite = 0; - break; - case 'w': - cvswrite = 1; - break; - case 'g': - /* - * force full group write perms (used for shared checked-out - * source trees, see manual page) - */ - umask(umask(077) & 007); - break; - case 't': - trace = 1; - break; - case 'R': - readonlyfs = 1; - logoff = 1; - break; - case 'n': - noexec = 1; - logoff = 1; - break; - case 'v': - (void) fputs ("\n", stdout); - version (0, (char **) NULL); - (void) fputs ("\n", stdout); - (void) fputs ("\ -Copyright (C) 2006 Free Software Foundation, Inc.\n\ -\n\ -Senior active maintainers include Larry Jones, Derek R. Price,\n\ -and Mark D. Baushke. Please see the AUTHORS and README files from the CVS\n\ -distribution kit for a complete list of contributors and copyrights.\n", - stdout); - (void) fputs ("\n", stdout); - (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout); - (void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout); - (void) fputs ("\n", stdout); - - (void) fputs ("Specify the --help option for further information about CVS\n", stdout); - -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems - * on NT and OS2 or dealing with windows and arguments on Mac. - */ - SYSTEM_CLEANUP (); -#endif - exit (0); - break; - case 'b': - /* This option used to specify the directory for RCS - executables. But since we don't run them any more, - this is a noop. Silently ignore it so that .cvsrc - and scripts and inetd.conf and such can work with - either new or old CVS. */ - break; - case 'T': - if (free_Tmpdir) free (Tmpdir); - Tmpdir = xstrdup (optarg); - free_Tmpdir = 1; - tmpdir_update_env = 1; /* need to update environment */ - break; - case 'e': - if (free_Editor) free (Editor); - Editor = xstrdup (optarg); - free_Editor = 1; - break; - case 'd': - if (CVSroot_cmdline != NULL) - free (CVSroot_cmdline); - CVSroot_cmdline = xstrdup (optarg); - break; - case 'H': - help = 1; - break; - case 'f': - use_cvsrc = 0; /* unnecessary, since we've done it above */ - break; - case 'z': - gzip_level = strtol (optarg, &end, 10); - if (*end != '\0' || gzip_level < 0 || gzip_level > 9) - error (1, 0, - "gzip compression level must be between 0 and 9"); - /* If no CLIENT_SUPPORT, we just silently ignore the gzip - * level, so that users can have it in their .cvsrc and not - * cause any trouble. - * - * We still parse the argument to -z for correctness since - * one user complained of being bitten by a run of - * `cvs -z -n up' which read -n as the argument to -z without - * complaining. */ - break; - case 's': - variable_set (optarg); - break; - case 'x': -#ifdef CLIENT_SUPPORT - cvsencrypt = 1; -#endif /* CLIENT_SUPPORT */ - /* If no CLIENT_SUPPORT, ignore -x, so that users can - have it in their .cvsrc and not cause any trouble. - If no ENCRYPTION, we still accept -x, but issue an - error if we are being run as a client. */ - break; - case 'a': -#ifdef CLIENT_SUPPORT - cvsauthenticate = 1; -#endif - /* If no CLIENT_SUPPORT, ignore -a, so that users can - have it in their .cvsrc and not cause any trouble. - We will issue an error later if stream - authentication is not supported. */ - break; - case 'U': -#ifdef SERVER_SUPPORT - require_real_user = 1; -#endif - break; - case '?': - default: - usage (usg); - } - } - - argc -= optind; - argv += optind; - if (argc < 1) - usage (usg); - - - /* Look up the command name. */ - - cvs_cmd_name = argv[0]; - for (cm = cmds; cm->fullname; cm++) - { - if (cm->nick1 && !strcmp (cvs_cmd_name, cm->nick1)) - break; - if (cm->nick2 && !strcmp (cvs_cmd_name, cm->nick2)) - break; - if (!strcmp (cvs_cmd_name, cm->fullname)) - break; - } - - if (!cm->fullname) - { - fprintf (stderr, "Unknown command: `%s'\n\n", cvs_cmd_name); - usage (cmd_usage); - } - else - cvs_cmd_name = cm->fullname; /* Global pointer for later use */ - - if (help) - { - argc = -1; /* some functions only check for this */ - err = (*(cm->func)) (argc, argv); - } - else - { - /* The user didn't ask for help, so go ahead and authenticate, - set up CVSROOT, and the rest of it. */ - - /* The UMASK environment variable isn't handled with the - others above, since we don't want to signal errors if the - user has asked for help. This won't work if somebody adds - a command-line flag to set the umask, since we'll have to - parse it before we get here. */ - - if ((cp = getenv (CVSUMASK_ENV)) != NULL) - { - /* FIXME: Should be accepting symbolic as well as numeric mask. */ - cvsumask = strtol (cp, &end, 8) & 0777; - if (*end != '\0') - error (1, errno, "invalid umask value in %s (%s)", - CVSUMASK_ENV, cp); - } - -#ifdef SERVER_SUPPORT - -# ifdef HAVE_KERBEROS - /* If we are invoked with a single argument "kserver", then we are - running as Kerberos server as root. Do the authentication as - the very first thing, to minimize the amount of time we are - running as root. */ - if (strcmp (cvs_cmd_name, "kserver") == 0) - { - kserver_authenticate_connection (); - - /* Pretend we were invoked as a plain server. */ - cvs_cmd_name = "server"; - } -# endif /* HAVE_KERBEROS */ - - -# if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI) - if (strcmp (cvs_cmd_name, "pserver") == 0) - { - /* The reason that --allow-root is not a command option - is mainly the comment in server() about how argc,argv - might be from .cvsrc. I'm not sure about that, and - I'm not sure it is only true of command options, but - it seems easier to make it a global option. */ - - /* Gets username and password from client, authenticates, then - switches to run as that user and sends an ACK back to the - client. */ - pserver_authenticate_connection (); - - /* Pretend we were invoked as a plain server. */ - cvs_cmd_name = "server"; - } -# endif /* AUTH_SERVER_SUPPORT || HAVE_GSSAPI */ -#endif /* SERVER_SUPPORT */ - - server_active = strcmp (cvs_cmd_name, "server") == 0; - - /* This is only used for writing into the history file. For - remote connections, it might be nice to have hostname - and/or remote path, on the other hand I'm not sure whether - it is worth the trouble. */ - - if (server_active) - CurDir = xstrdup ("<remote>"); - else - { - CurDir = xgetwd (); - if (CurDir == NULL) - error (1, errno, "cannot get working directory"); - } - - if (Tmpdir == NULL || Tmpdir[0] == '\0') - { - if (free_Tmpdir) free (Tmpdir); - Tmpdir = "/tmp"; - } - -#ifdef HAVE_PUTENV - if (tmpdir_update_env) - { - char *env; - env = xmalloc (strlen (TMPDIR_ENV) + strlen (Tmpdir) + 1 + 1); - (void) sprintf (env, "%s=%s", TMPDIR_ENV, Tmpdir); - (void) putenv (env); - /* do not free env, as putenv has control of it */ - } - { - char *env; - env = xmalloc (sizeof "CVS_PID=" + 32); /* XXX pid < 10^32 */ - (void) sprintf (env, "CVS_PID=%ld", (long) getpid ()); - (void) putenv (env); - } -#endif - -#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); -#endif -#ifdef SIGINT - (void) SIG_register (SIGINT, main_cleanup); -#endif -#ifdef SIGQUIT - (void) SIG_register (SIGQUIT, main_cleanup); -#endif -#ifdef SIGPIPE - (void) SIG_register (SIGPIPE, main_cleanup); -#endif -#ifdef SIGTERM - (void) SIG_register (SIGTERM, main_cleanup); -#endif -#endif /* !DONT_USE_SIGNALS */ - - gethostname(hostname, sizeof (hostname)); - -#ifdef KLUDGE_FOR_WNT_TESTSUITE - /* Probably the need for this will go away at some point once - we call fflush enough places (e.g. fflush (stdout) in - cvs_outerr). */ - (void) setvbuf (stdout, (char *) NULL, _IONBF, 0); - (void) setvbuf (stderr, (char *) NULL, _IONBF, 0); -#endif /* KLUDGE_FOR_WNT_TESTSUITE */ - - if (use_cvsrc) - read_cvsrc (&argc, &argv, cvs_cmd_name); - - /* Fiddling with CVSROOT doesn't make sense if we're running - * in server mode, since the client will send the repository - * directory after the connection is made. - */ - if (!server_active) - { - /* First check if a root was set via the command line. */ - if (CVSroot_cmdline) - { - if (!(CVSroot_parsed = parse_cvsroot (CVSroot_cmdline))) - error (1, 0, "Bad CVSROOT: `%s'.", CVSroot_cmdline); - } - - /* See if we are able to find a 'better' value for CVSroot - * in the CVSADM_ROOT directory. - * - * "cvs import" shouldn't check CVS/Root; in general it - * ignores CVS directories and CVS/Root is likely to - * specify a different repository than the one we are - * importing to, but if this is not import and no root was - * specified on the command line, set the root from the - * CVS/Root file. - */ - if (!CVSroot_parsed - && !(cm->attr & CVS_CMD_IGNORE_ADMROOT) - ) - CVSroot_parsed = Name_Root (NULL, NULL); - - /* Now, if there is no root on the command line and we didn't find - * one in a file, set it via the $CVSROOT env var. - */ - if (!CVSroot_parsed) - { - char *tmp = getenv (CVSROOT_ENV); - if (tmp) - { - if (!(CVSroot_parsed = parse_cvsroot (tmp))) - error (1, 0, "Bad CVSROOT: `%s'.", tmp); - cvsroot_update_env = 0; - } - } - -#ifdef CVSROOT_DFLT - if (!CVSroot_parsed) - { - if (!(CVSroot_parsed = parse_cvsroot (CVSROOT_DFLT))) - error (1, 0, "Bad CVSROOT: `%s'.", CVSROOT_DFLT); - } -#endif /* CVSROOT_DFLT */ - - /* Now we've reconciled CVSROOT from the command line, the - CVS/Root file, and the environment variable. Do the - last sanity checks on the variable. */ - if (!CVSroot_parsed) - { - error (0, 0, - "No CVSROOT specified! Please use the `-d' option"); - error (1, 0, - "or set the %s environment variable.", CVSROOT_ENV); - } - } - - /* Here begins the big loop over unique cvsroot values. We - need to call do_recursion once for each unique value found - in CVS/Root. Prime the list with the current value. */ - - /* Create the list. */ - assert (root_directories == NULL); - root_directories = getlist (); - - /* Prime it. */ - if (CVSroot_parsed) - { - Node *n; - n = getnode (); - n->type = NT_UNKNOWN; - n->key = xstrdup (CVSroot_parsed->original); - n->data = CVSroot_parsed; - - if (addnode (root_directories, n)) - error (1, 0, "cannot add initial CVSROOT %s", n->key); - } - - assert (current_parsed_root == NULL); - - /* If we're running the server, we want to execute this main - loop once and only once (we won't be serving multiple roots - from this connection, so there's no need to do it more than - once). To get out of the loop, we perform a "break" at the - end of things. */ - - while (server_active || - walklist (root_directories, set_root_directory, NULL)) - { - /* Fiddling with CVSROOT doesn't make sense if we're running - in server mode, since the client will send the repository - directory after the connection is made. */ - - if (!server_active) - { - /* Now we're 100% sure that we have a valid CVSROOT - variable. Parse it to see if we're supposed to do - remote accesses or use a special access method. */ - - if (trace) - fprintf (stderr, "%s-> main loop with CVSROOT=%s\n", - CLIENT_SERVER_STR, current_parsed_root->original); - - /* - * Check to see if the repository exists. - */ - if (!current_parsed_root->isremote) - { - char *path; - int save_errno; - - path = xmalloc (strlen (current_parsed_root->directory) - + strlen (CVSROOTADM) + 2); - sprintf (path, "%s/%s", current_parsed_root->directory, - CVSROOTADM); - if (!isaccessible (path, R_OK | X_OK)) - { - save_errno = errno; - /* If this is "cvs init", the root need not exist yet. - */ - if (strcmp (cvs_cmd_name, "init")) - error (1, save_errno, "%s", path); - } - free (path); - } - -#ifdef HAVE_PUTENV - /* Update the CVSROOT environment variable. */ - if (cvsroot_update_env) - { - static char *prev; - char *env; - - env = xmalloc (strlen (CVSROOT_ENV) - + strlen (current_parsed_root->original) - + 2); - sprintf (env, "%s=%s", CVSROOT_ENV, - current_parsed_root->original); - (void) putenv (env); - /* 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 - } - - /* Parse the CVSROOT/config file, but only for local. For the - server, we parse it after we know $CVSROOT. For the - client, it doesn't get parsed at all, obviously. The - presence of the parse_config call here is not mean to - predetermine whether CVSROOT/config overrides things from - read_cvsrc and other such places or vice versa. That sort - of thing probably needs more thought. */ - if (!server_active && !current_parsed_root->isremote) - { - /* If there was an error parsing the config file, parse_config - already printed an error. We keep going. Why? Because - if we didn't, then there would be no way to check in a new - CVSROOT/config file to fix the broken one! */ - parse_config (current_parsed_root->directory); - - /* Now is a convenient time to read CVSROOT/options */ - parseopts(current_parsed_root->directory); - } - -#ifdef CLIENT_SUPPORT - /* Need to check for current_parsed_root != NULL here since - * we could still be in server mode before the server function - * gets called below and sets the root - */ - if (current_parsed_root != NULL && current_parsed_root->isremote) - { - /* Create a new list for directory names that we've - sent to the server. */ - if (dirs_sent_to_server != NULL) - dellist (&dirs_sent_to_server); - dirs_sent_to_server = getlist (); - } -#endif - - err = (*(cm->func)) (argc, argv); - - /* Mark this root directory as done. When the server is - active, our list will be empty -- don't try and - remove it from the list. */ - - if (!server_active) - { - Node *n = findnode (root_directories, - current_parsed_root->original); - assert (n != NULL); - assert (n->data != NULL); - free_cvsroot_t (n->data); - n->data = NULL; - current_parsed_root = NULL; - } - - if (server_active) - { - server_active = 0; - break; - } - } /* end of loop for cvsroot values */ - - dellist (&root_directories); - } /* end of stuff that gets done if the user DOESN'T ask for help */ - - Lock_Cleanup (); - - /* It's okay to cast out the const below since we know we allocated this in - * this function. The const was to keep other functions from messing with - * this. - */ - free ((char *)program_path); - if (CVSroot_cmdline != NULL) - free (CVSroot_cmdline); - if (free_Editor) - free (Editor); - if (free_Tmpdir) - free (Tmpdir); - root_allow_free (); - -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - - /* This is exit rather than return because apparently that keeps - some tools which check for memory leaks happier. */ - exit (err ? EXIT_FAILURE : 0); - /* Keep picky/stupid compilers (e.g. Visual C++ 5.0) happy. */ - return 0; -} - -char * -Make_Date (rawdate) - char *rawdate; -{ - time_t unixtime; - - unixtime = get_date (rawdate, (struct timeb *) NULL); - if (unixtime == (time_t) - 1) - error (1, 0, "Can't parse date/time: %s", rawdate); - return date_from_time_t (unixtime); -} - -/* Convert a time_t to an RCS format date. This is mainly for the - use of "cvs history", because the CVSROOT/history file contains - time_t format dates; most parts of CVS will want to avoid using - time_t's directly, and instead use RCS_datecmp, Make_Date, &c. - Assuming that the time_t is in GMT (as it generally should be), - then the result will be in GMT too. - - Returns a newly malloc'd string. */ - -char * -date_from_time_t (unixtime) - time_t unixtime; -{ - struct tm *ftm; - char date[MAXDATELEN]; - char *ret; - - ftm = gmtime (&unixtime); - if (ftm == NULL) - /* This is a system, like VMS, where the system clock is in local - time. Hopefully using localtime here matches the "zero timezone" - hack I added to get_date (get_date of course being the relevant - issue for Make_Date, and for history.c too I think). */ - ftm = localtime (&unixtime); - - (void) sprintf (date, DATEFORM, - ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), - ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, - ftm->tm_min, ftm->tm_sec); - ret = xstrdup (date); - return (ret); -} - -/* Convert a date to RFC822/1123 format. This is used in contexts like - dates to send in the protocol; it should not vary based on locale or - other such conventions for users. We should have another routine which - does that kind of thing. - - The SOURCE date is in our internal RCS format. DEST should point to - storage managed by the caller, at least MAXDATELEN characters. */ -void -date_to_internet (dest, source) - char *dest; - const char *source; -{ - struct tm date; - - date_to_tm (&date, source); - tm_to_internet (dest, &date); -} - -void -date_to_tm (dest, source) - struct tm *dest; - const char *source; -{ - if (sscanf (source, SDATEFORM, - &dest->tm_year, &dest->tm_mon, &dest->tm_mday, - &dest->tm_hour, &dest->tm_min, &dest->tm_sec) - != 6) - /* Is there a better way to handle errors here? I made this - non-fatal in case we are called from the code which can't - deal with fatal errors. */ - error (0, 0, "internal error: bad date %s", source); - - if (dest->tm_year > 100) - dest->tm_year -= 1900; - - dest->tm_mon -= 1; -} - -/* Convert a date to RFC822/1123 format. This is used in contexts like - dates to send in the protocol; it should not vary based on locale or - other such conventions for users. We should have another routine which - does that kind of thing. - - The SOURCE date is a pointer to a struct tm. DEST should point to - storage managed by the caller, at least MAXDATELEN characters. */ -void -tm_to_internet (dest, source) - char *dest; - const struct tm *source; -{ - /* Just to reiterate, these strings are from RFC822 and do not vary - according to locale. */ - static const char *const month_names[] = - {"Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - - sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", source->tm_mday, - source->tm_mon < 0 || source->tm_mon > 11 ? "???" : month_names[source->tm_mon], - source->tm_year + 1900, source->tm_hour, source->tm_min, source->tm_sec); -} - -void -usage (cpp) - register const char *const *cpp; -{ - (void) fprintf (stderr, *cpp++, program_name, cvs_cmd_name); - for (; *cpp; cpp++) - (void) fprintf (stderr, *cpp); - error_exit (); -} - -void -parseopts(root) - const char *root; -{ - char path[PATH_MAX]; - int save_errno; - char buf[1024]; - const char *p; - char *q; - FILE *fp; - - if (root == NULL) { - printf("no CVSROOT in parseopts\n"); - return; - } - p = strchr (root, ':'); - if (p) - p++; - else - p = root; - if (p == NULL) { - printf("mangled CVSROOT in parseopts\n"); - return; - } - (void) sprintf (path, "%s/%s/%s", p, CVSROOTADM, CVSROOTADM_OPTIONS); - if ((fp = fopen(path, "r")) != NULL) { - while (fgets(buf, sizeof buf, fp) != NULL) { - if (buf[0] == '#') - continue; - q = strrchr(buf, '\n'); - if (q) - *q = '\0'; - - if (!strcmp(buf, "iso8601")) { - datesep = '-'; - } - if (!strncmp(buf, "tag=", 4)) { - char *what; - char *rcs_localid; - - rcs_localid = buf + 4; - RCS_setlocalid(rcs_localid); - } - if (!strncmp(buf, "tagexpand=", 10)) { - char *what; - char *rcs_incexc; - - rcs_incexc = buf + 10; - RCS_setincexc(rcs_incexc); - } - /* - * OpenBSD has a "umask=" and "dlimit=" command, we silently - * ignore them here since they are not much use to us. cvsumask - * defaults to 002 already, and the dlimit (data size limit) - * should really be handled elsewhere (eg: login.conf). - */ - } - fclose(fp); - } -} diff --git a/contrib/cvs/src/mkmodules.c b/contrib/cvs/src/mkmodules.c deleted file mode 100644 index 751d4c7..0000000 --- a/contrib/cvs/src/mkmodules.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * Copyright (C) 1986-2008 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS kit. */ - -#include <assert.h> -#include "cvs.h" -#include "getline.h" -#include "history.h" -#include "savecwd.h" - -#ifndef DBLKSIZ -#define DBLKSIZ 4096 /* since GNU ndbm doesn't define it */ -#endif - -static int checkout_file PROTO((char *file, char *temp)); -static char *make_tempfile PROTO((void)); -static void rename_rcsfile PROTO((char *temp, char *real)); - -#ifndef MY_NDBM -static void rename_dbmfile PROTO((char *temp)); -static void write_dbmfile PROTO((char *temp)); -#endif /* !MY_NDBM */ - -/* Structure which describes an administrative file. */ -struct admin_file { - /* Name of the file, within the CVSROOT directory. */ - char *filename; - - /* This is a one line description of what the file is for. It is not - currently used, although one wonders whether it should be, somehow. - If NULL, then don't process this file in mkmodules (FIXME?: a bit of - a kludge; probably should replace this with a flags field). */ - char *errormsg; - - /* Contents which the file should have in a new repository. To avoid - problems with brain-dead compilers which choke on long string constants, - this is a pointer to an array of char * terminated by NULL--each of - the strings is concatenated. - - If this field is NULL, the file is not created in a new - repository, but it can be added with "cvs add" (just as if one - had created the repository with a version of CVS which didn't - know about the file) and the checked-out copy will be updated - without having to add it to checkoutlist. */ - const char * const *contents; -}; - -static const char *const loginfo_contents[] = { - "# The \"loginfo\" file controls where \"cvs commit\" log information\n", - "# is sent. The first entry on a line is a regular expression which must match\n", - "# the directory that the change is being made to, relative to the\n", - "# $CVSROOT. If a match is found, then the remainder of the line is a filter\n", - "# program that should expect log information on its standard input.\n", - "#\n", - "# If the repository name does not match any of the regular expressions in this\n", - "# file, the \"DEFAULT\" line is used, if it is specified.\n", - "#\n", - "# If the name ALL appears as a regular expression it is always used\n", - "# in addition to the first matching regex or DEFAULT.\n", - "#\n", - "# You may specify a format string as part of the\n", - "# filter. The string is composed of a `%' followed\n", - "# by a single format character, or followed by a set of format\n", - "# characters surrounded by `{' and `}' as separators. The format\n", - "# characters are:\n", - "#\n", - "# s = file name\n", - "# V = old version number (pre-checkin)\n", - "# v = new version number (post-checkin)\n", - "#\n", - "# For example:\n", - "#DEFAULT (echo \"\"; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog\n", - "# or\n", - "#DEFAULT (echo \"\"; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog\n", - NULL -}; - -static const char *const rcsinfo_contents[] = { - "# The \"rcsinfo\" file is used to control templates with which the editor\n", - "# is invoked on commit and import.\n", - "#\n", - "# The first entry on a line is a regular expression which is tested\n", - "# against the directory that the change is being made to, relative to the\n", - "# $CVSROOT. For the first match that is found, then the remainder of the\n", - "# line is the name of the file that contains the template.\n", - "#\n", - "# If the repository name does not match any of the regular expressions in this\n", - "# file, the \"DEFAULT\" line is used, if it is specified.\n", - "#\n", - "# If the name \"ALL\" appears as a regular expression it is always used\n", - "# in addition to the first matching regex or \"DEFAULT\".\n", - NULL -}; - -static const char *const editinfo_contents[] = { - "# The \"editinfo\" file is used to allow verification of logging\n", - "# information. It works best when a template (as specified in the\n", - "# rcsinfo file) is provided for the logging procedure. Given a\n", - "# template with locations for, a bug-id number, a list of people who\n", - "# reviewed the code before it can be checked in, and an external\n", - "# process to catalog the differences that were code reviewed, the\n", - "# following test can be applied to the code:\n", - "#\n", - "# Making sure that the entered bug-id number is correct.\n", - "# Validating that the code that was reviewed is indeed the code being\n", - "# checked in (using the bug-id number or a seperate review\n", - "# number to identify this particular code set.).\n", - "#\n", - "# If any of the above test failed, then the commit would be aborted.\n", - "#\n", - "# Actions such as mailing a copy of the report to each reviewer are\n", - "# better handled by an entry in the loginfo file.\n", - "#\n", - "# One thing that should be noted is the the ALL keyword is not\n", - "# supported. There can be only one entry that matches a given\n", - "# repository.\n", - NULL -}; - -static const char *const verifymsg_contents[] = { - "# The \"verifymsg\" file is used to allow verification of logging\n", - "# information. It works best when a template (as specified in the\n", - "# rcsinfo file) is provided for the logging procedure. Given a\n", - "# template with locations for, a bug-id number, a list of people who\n", - "# reviewed the code before it can be checked in, and an external\n", - "# process to catalog the differences that were code reviewed, the\n", - "# following test can be applied to the code:\n", - "#\n", - "# Making sure that the entered bug-id number is correct.\n", - "# Validating that the code that was reviewed is indeed the code being\n", - "# checked in (using the bug-id number or a seperate review\n", - "# number to identify this particular code set.).\n", - "#\n", - "# If any of the above test failed, then the commit would be aborted.\n", - "#\n", - "# Actions such as mailing a copy of the report to each reviewer are\n", - "# better handled by an entry in the loginfo file.\n", - "#\n", - "# One thing that should be noted is the the ALL keyword is not\n", - "# supported. There can be only one entry that matches a given\n", - "# repository.\n", - NULL -}; - -static const char *const commitinfo_contents[] = { - "# The \"commitinfo\" file is used to control pre-commit checks.\n", - "# The filter on the right is invoked with the repository and a list \n", - "# of files to check. A non-zero exit of the filter program will \n", - "# cause the commit to be aborted.\n", - "#\n", - "# The first entry on a line is a regular expression which is tested\n", - "# against the directory that the change is being committed to, relative\n", - "# to the $CVSROOT. For the first match that is found, then the remainder\n", - "# of the line is the name of the filter to run.\n", - "#\n", - "# If the repository name does not match any of the regular expressions in this\n", - "# file, the \"DEFAULT\" line is used, if it is specified.\n", - "#\n", - "# If the name \"ALL\" appears as a regular expression it is always used\n", - "# in addition to the first matching regex or \"DEFAULT\".\n", - NULL -}; - -static const char *const taginfo_contents[] = { - "# The \"taginfo\" file is used to control pre-tag checks.\n", - "# The filter on the right is invoked with the following arguments:\n", - "#\n", - "# $1 -- tagname\n", - "# $2 -- operation \"add\" for tag, \"mov\" for tag -F, and \"del\" for tag -d\n", - "# $3 -- repository\n", - "# $4-> file revision [file revision ...]\n", - "#\n", - "# A non-zero exit of the filter program will cause the tag to be aborted.\n", - "#\n", - "# The first entry on a line is a regular expression which is tested\n", - "# against the directory that the change is being committed to, relative\n", - "# to the $CVSROOT. For the first match that is found, then the remainder\n", - "# of the line is the name of the filter to run.\n", - "#\n", - "# If the repository name does not match any of the regular expressions in this\n", - "# file, the \"DEFAULT\" line is used, if it is specified.\n", - "#\n", - "# If the name \"ALL\" appears as a regular expression it is always used\n", - "# in addition to the first matching regex or \"DEFAULT\".\n", - NULL -}; - -static const char *const checkoutlist_contents[] = { - "# The \"checkoutlist\" file is used to support additional version controlled\n", - "# administrative files in $CVSROOT/CVSROOT, such as template files.\n", - "#\n", - "# The first entry on a line is a filename which will be checked out from\n", - "# the corresponding RCS file in the $CVSROOT/CVSROOT directory.\n", - "# The remainder of the line is an error message to use if the file cannot\n", - "# be checked out.\n", - "#\n", - "# File format:\n", - "#\n", - "# [<whitespace>]<filename>[<whitespace><error message>]<end-of-line>\n", - "#\n", - "# comment lines begin with '#'\n", - NULL -}; - -static const char *const cvswrappers_contents[] = { - "# This file affects handling of files based on their names.\n", - "#\n", -#if 0 /* see comments in wrap_add in wrapper.c */ - "# The -t/-f options allow one to treat directories of files\n", - "# as a single file, or to transform a file in other ways on\n", - "# its way in and out of CVS.\n", - "#\n", -#endif - "# The -m option specifies whether CVS attempts to merge files.\n", - "#\n", - "# The -k option specifies keyword expansion (e.g. -kb for binary).\n", - "#\n", - "# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)\n", - "#\n", - "# wildcard [option value][option value]...\n", - "#\n", - "# where option is one of\n", - "# -f from cvs filter value: path to filter\n", - "# -t to cvs filter value: path to filter\n", - "# -m update methodology value: MERGE or COPY\n", - "# -k expansion mode value: b, o, kkv, &c\n", - "#\n", - "# and value is a single-quote delimited value.\n", - "# For example:\n", - "#*.gif -k 'b'\n", - NULL -}; - -static const char *const notify_contents[] = { - "# The \"notify\" file controls where notifications from watches set by\n", - "# \"cvs watch add\" or \"cvs edit\" are sent. The first entry on a line is\n", - "# a regular expression which is tested against the directory that the\n", - "# change is being made to, relative to the $CVSROOT. If it matches,\n", - "# then the remainder of the line is a filter program that should contain\n", - "# one occurrence of %s for the user to notify, and information on its\n", - "# standard input.\n", - "#\n", - "# \"ALL\" or \"DEFAULT\" can be used in place of the regular expression.\n", - "#\n", - "# For example:\n", - "#ALL mail -s \"CVS notification\" %s\n", - NULL -}; - -static const char *const modules_contents[] = { - "# Three different line formats are valid:\n", - "# key -a aliases...\n", - "# key [options] directory\n", - "# key [options] directory files...\n", - "#\n", - "# Where \"options\" are composed of:\n", - "# -o prog Run \"prog\" on \"cvs checkout\" of module.\n", - "# -e prog Run \"prog\" on \"cvs export\" of module.\n", - "# -t prog Run \"prog\" on \"cvs rtag\" of module.\n", - "# -u prog Run \"prog\" on \"cvs update\" of module.\n", - "# -d dir Place module in directory \"dir\" instead of module name.\n", - "# -l Top-level directory only -- do not recurse.\n", - "#\n", - "# NOTE: If you change any of the \"Run\" options above, you'll have to\n", - "# release and re-checkout any working directories of these modules.\n", - "#\n", - "# And \"directory\" is a path to a directory relative to $CVSROOT.\n", - "#\n", - "# The \"-a\" option specifies an alias. An alias is interpreted as if\n", - "# everything on the right of the \"-a\" had been typed on the command line.\n", - "#\n", - "# You can encode a module within a module by using the special '&'\n", - "# character to interpose another module into the current module. This\n", - "# can be useful for creating a module that consists of many directories\n", - "# spread out over the entire source repository.\n", - NULL -}; - -static const char *const config_contents[] = { - "# Set this to \"no\" if pserver shouldn't check system users/passwords\n", - "#SystemAuth=yes\n", - "\n", - "# Set `IgnoreUnknownConfigKeys' to `yes' to ignore unknown config\n", - "# keys which are supported in a future version of CVS.\n", - "# This option is intended to be useful as a transition for read-only\n", - "# mirror sites when sites may need to be updated later than the\n", - "# primary CVS repository.\n", - "#IgnoreUnknownConfigKeys=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 `" ALL_HISTORY_REC_TYPES "' to log all transactions to the\n", - "# history file, or a subset as needed (ie `TMAR' logs all write operations)\n", - "#LogHistory=" ALL_HISTORY_REC_TYPES "\n", - "\n", - "# Set `RereadLogAfterVerify' to `always' (the default) to allow the verifymsg\n", - "# script to change the log message. Set it to `stat' to force CVS to verify\n", - "# that the file has changed before reading it (this can take up to an extra\n", - "# second per directory being committed, so it is not recommended for large\n", - "# repositories. Set it to `never' (the previous CVS behavior) to prevent\n", - "# verifymsg scripts from changing the log message.\n", - "#RereadLogAfterVerify=always\n", - NULL -}; - -static const struct admin_file filelist[] = { - {CVSROOTADM_LOGINFO, - "no logging of 'cvs commit' messages is done without a %s file", - &loginfo_contents[0]}, - {CVSROOTADM_RCSINFO, - "a %s file can be used to configure 'cvs commit' templates", - rcsinfo_contents}, - {CVSROOTADM_EDITINFO, - "a %s file can be used to validate log messages", - editinfo_contents}, - {CVSROOTADM_VERIFYMSG, - "a %s file can be used to validate log messages", - verifymsg_contents}, - {CVSROOTADM_COMMITINFO, - "a %s file can be used to configure 'cvs commit' checking", - commitinfo_contents}, - {CVSROOTADM_TAGINFO, - "a %s file can be used to configure 'cvs tag' checking", - taginfo_contents}, - {CVSROOTADM_IGNORE, - "a %s file can be used to specify files to ignore", - NULL}, - {CVSROOTADM_CHECKOUTLIST, - "a %s file can specify extra CVSROOT files to auto-checkout", - checkoutlist_contents}, - {CVSROOTADM_WRAPPER, - "a %s file can be used to specify files to treat as wrappers", - cvswrappers_contents}, - {CVSROOTADM_NOTIFY, - "a %s file can be used to specify where notifications go", - notify_contents}, - {CVSROOTADM_MODULES, - /* modules is special-cased in mkmodules. */ - NULL, - modules_contents}, - {CVSROOTADM_READERS, - "a %s file specifies read-only users", - NULL}, - {CVSROOTADM_WRITERS, - "a %s file specifies read/write users", - NULL}, - - /* Some have suggested listing CVSROOTADM_PASSWD here too. This - would mean that CVS commands which operate on the - CVSROOTADM_PASSWD file would transmit hashed passwords over the - net. This might seem to be no big deal, as pserver normally - transmits cleartext passwords, but the difference is that - CVSROOTADM_PASSWD contains *all* passwords, not just the ones - currently being used. For example, it could be too easy to - accidentally give someone readonly access to CVSROOTADM_PASSWD - (e.g. via anonymous CVS or cvsweb), and then if there are any - guessable passwords for read/write access (usually there will be) - they get read/write access. - - Another worry is the implications of storing old passwords--if - someone used a password in the past they might be using it - elsewhere, using a similar password, etc, and so saving old - passwords, even hashed, is probably not a good idea. */ - - {CVSROOTADM_CONFIG, - "a %s file configures various behaviors", - config_contents}, - {NULL, NULL, NULL} -}; - -/* Rebuild the checked out administrative files in directory DIR. */ -int -mkmodules (dir) - char *dir; -{ - struct saved_cwd cwd; - char *temp; - char *cp, *last, *fname; -#ifdef MY_NDBM - DBM *db; -#endif - FILE *fp; - char *line = NULL; - size_t line_allocated = 0; - const struct admin_file *fileptr; - - if (noexec) - return 0; - - if (save_cwd (&cwd)) - error_exit (); - - if ( CVS_CHDIR (dir) < 0) - error (1, errno, "cannot chdir to %s", dir); - - /* - * First, do the work necessary to update the "modules" database. - */ - temp = make_tempfile (); - switch (checkout_file (CVSROOTADM_MODULES, temp)) - { - - case 0: /* everything ok */ -#ifdef MY_NDBM - /* open it, to generate any duplicate errors */ - if ((db = dbm_open (temp, O_RDONLY, 0666)) != NULL) - dbm_close (db); -#else - write_dbmfile (temp); - rename_dbmfile (temp); -#endif - rename_rcsfile (temp, CVSROOTADM_MODULES); - break; - - default: - error (0, 0, - "'cvs checkout' is less functional without a %s file", - CVSROOTADM_MODULES); - break; - } /* switch on checkout_file() */ - - if (unlink_file (temp) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", temp); - free (temp); - - /* Checkout the files that need it in CVSROOT dir */ - for (fileptr = filelist; fileptr && fileptr->filename; fileptr++) { - if (fileptr->errormsg == NULL) - continue; - temp = make_tempfile (); - if (checkout_file (fileptr->filename, temp) == 0) - rename_rcsfile (temp, fileptr->filename); -#if 0 - /* - * If there was some problem other than the file not existing, - * checkout_file already printed a real error message. If the - * file does not exist, it is harmless--it probably just means - * that the repository was created with an old version of CVS - * which didn't have so many files in CVSROOT. - */ - else if (fileptr->errormsg) - error (0, 0, fileptr->errormsg, fileptr->filename); -#endif - if (unlink_file (temp) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", temp); - free (temp); - } - - fp = CVS_FOPEN (CVSROOTADM_CHECKOUTLIST, "r"); - if (fp) - { - /* - * File format: - * [<whitespace>]<filename>[<whitespace><error message>]<end-of-line> - * - * comment lines begin with '#' - */ - while (getline (&line, &line_allocated, fp) >= 0) - { - /* skip lines starting with # */ - if (line[0] == '#') - continue; - - if ((last = strrchr (line, '\n')) != NULL) - *last = '\0'; /* strip the newline */ - - /* Skip leading white space. */ - for (fname = line; - *fname && isspace ((unsigned char) *fname); - fname++) - ; - - /* Find end of filename. */ - for (cp = fname; *cp && !isspace ((unsigned char) *cp); cp++) - ; - *cp = '\0'; - - temp = make_tempfile (); - if (checkout_file (fname, temp) == 0) - { - rename_rcsfile (temp, fname); - } - else - { - /* Skip leading white space before the error message. */ - for (cp++; - cp < last && *cp && isspace ((unsigned char) *cp); - cp++) - ; - if (cp < last && *cp) - error (0, 0, "%s", cp); - } - if (unlink_file (temp) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", temp); - free (temp); - } - if (line) - free (line); - if (ferror (fp)) - error (0, errno, "cannot read %s", CVSROOTADM_CHECKOUTLIST); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", CVSROOTADM_CHECKOUTLIST); - } - else - { - /* Error from CVS_FOPEN. */ - if (!existence_error (errno)) - error (0, errno, "cannot open %s", CVSROOTADM_CHECKOUTLIST); - } - - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - - return (0); -} - -/* - * Yeah, I know, there are NFS race conditions here. - */ -static char * -make_tempfile () -{ - static int seed = 0; - int fd; - char *temp; - - if (seed == 0) - seed = getpid (); - temp = xmalloc (sizeof (BAKPREFIX) + 40); - while (1) - { - (void) sprintf (temp, "%s%d", BAKPREFIX, seed++); - if ((fd = CVS_OPEN (temp, O_CREAT|O_EXCL|O_RDWR, 0666)) != -1) - break; - if (errno != EEXIST) - error (1, errno, "cannot create temporary file %s", temp); - } - if (close(fd) < 0) - error(1, errno, "cannot close temporary file %s", temp); - return temp; -} - -/* Get a file. If the file does not exist, return 1 silently. If - there is an error, print a message and return 1 (FIXME: probably - not a very clean convention). On success, return 0. */ - -static int -checkout_file (file, temp) - char *file; - char *temp; -{ - char *rcs; - RCSNode *rcsnode; - int retcode = 0; - - if (noexec) - return 0; - - rcs = xmalloc (strlen (file) + 5); - strcpy (rcs, file); - strcat (rcs, RCSEXT); - if (!isfile (rcs)) - { - free (rcs); - return (1); - } - - rcsnode = RCS_parsercsfile (rcs); - if (!rcsnode) - { - /* Probably not necessary (?); RCS_parsercsfile already printed a - message. */ - error (0, 0, "Failed to parse `%s'.", rcs); - free (rcs); - return 1; - } - - retcode = RCS_checkout (rcsnode, NULL, NULL, NULL, NULL, temp, - (RCSCHECKOUTPROC) NULL, (void *) NULL); - if (retcode != 0) - { - /* Probably not necessary (?); RCS_checkout already printed a - message. */ - error (0, 0, "failed to check out %s file", - file); - } - freercsnode (&rcsnode); - free (rcs); - return (retcode); -} - -#ifndef MY_NDBM - -static void -write_dbmfile (temp) - char *temp; -{ - char line[DBLKSIZ], value[DBLKSIZ]; - FILE *fp; - DBM *db; - char *cp, *vp; - datum key, val; - int len, cont, err = 0; - - fp = open_file (temp, "r"); - if ((db = dbm_open (temp, O_RDWR | O_CREAT | O_TRUNC, 0666)) == NULL) - error (1, errno, "cannot open dbm file %s for creation", temp); - for (cont = 0; fgets (line, sizeof (line), fp) != NULL;) - { - if ((cp = strrchr (line, '\n')) != NULL) - *cp = '\0'; /* strip the newline */ - - /* - * Add the line to the value, at the end if this is a continuation - * line; otherwise at the beginning, but only after any trailing - * backslash is removed. - */ - vp = value; - if (cont) - vp += strlen (value); - - /* - * See if the line we read is a continuation line, and strip the - * backslash if so. - */ - len = strlen (line); - if (len > 0) - cp = &line[len - 1]; - else - cp = line; - if (*cp == '\\') - { - cont = 1; - *cp = '\0'; - } - else - { - cont = 0; - } - (void) strcpy (vp, line); - if (value[0] == '#') - continue; /* comment line */ - vp = value; - while (*vp && isspace ((unsigned char) *vp)) - vp++; - if (*vp == '\0') - continue; /* empty line */ - - /* - * If this was not a continuation line, add the entry to the database - */ - if (!cont) - { - key.dptr = vp; - while (*vp && !isspace ((unsigned char) *vp)) - vp++; - key.dsize = vp - key.dptr; - *vp++ = '\0'; /* NULL terminate the key */ - while (*vp && isspace ((unsigned char) *vp)) - vp++; /* skip whitespace to value */ - if (*vp == '\0') - { - error (0, 0, "warning: NULL value for key `%s'", key.dptr); - continue; - } - val.dptr = vp; - val.dsize = strlen (vp); - if (dbm_store (db, key, val, DBM_INSERT) == 1) - { - error (0, 0, "duplicate key found for `%s'", key.dptr); - err++; - } - } - } - dbm_close (db); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", temp); - if (err) - { - /* I think that the size of the buffer needed here is - just determined by sizeof (CVSROOTADM_MODULES), the - filenames created by make_tempfile, and other things that won't - overflow. */ - char dotdir[50], dotpag[50], dotdb[50]; - - (void) sprintf (dotdir, "%s.dir", temp); - (void) sprintf (dotpag, "%s.pag", temp); - (void) sprintf (dotdb, "%s.db", temp); - if (unlink_file (dotdir) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", dotdir); - if (unlink_file (dotpag) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", dotpag); - if (unlink_file (dotdb) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", dotdb); - error (1, 0, "DBM creation failed; correct above errors"); - } -} - -static void -rename_dbmfile (temp) - char *temp; -{ - /* I think that the size of the buffer needed here is - just determined by sizeof (CVSROOTADM_MODULES), the - filenames created by make_tempfile, and other things that won't - overflow. */ - char newdir[50], newpag[50], newdb[50]; - char dotdir[50], dotpag[50], dotdb[50]; - char bakdir[50], bakpag[50], bakdb[50]; - - int dir1_errno = 0, pag1_errno = 0, db1_errno = 0; - int dir2_errno = 0, pag2_errno = 0, db2_errno = 0; - int dir3_errno = 0, pag3_errno = 0, db3_errno = 0; - - (void) sprintf (dotdir, "%s.dir", CVSROOTADM_MODULES); - (void) sprintf (dotpag, "%s.pag", CVSROOTADM_MODULES); - (void) sprintf (dotdb, "%s.db", CVSROOTADM_MODULES); - (void) sprintf (bakdir, "%s%s.dir", BAKPREFIX, CVSROOTADM_MODULES); - (void) sprintf (bakpag, "%s%s.pag", BAKPREFIX, CVSROOTADM_MODULES); - (void) sprintf (bakdb, "%s%s.db", BAKPREFIX, CVSROOTADM_MODULES); - (void) sprintf (newdir, "%s.dir", temp); - (void) sprintf (newpag, "%s.pag", temp); - (void) sprintf (newdb, "%s.db", temp); - - (void) chmod (newdir, 0666); - (void) chmod (newpag, 0666); - (void) chmod (newdb, 0666); - - /* don't mess with me */ - SIG_beginCrSect (); - - /* rm .#modules.dir .#modules.pag */ - if (unlink_file (bakdir) < 0) - dir1_errno = errno; - if (unlink_file (bakpag) < 0) - pag1_errno = errno; - if (unlink_file (bakdb) < 0) - db1_errno = errno; - - /* mv modules.dir .#modules.dir */ - if (CVS_RENAME (dotdir, bakdir) < 0) - dir2_errno = errno; - /* mv modules.pag .#modules.pag */ - if (CVS_RENAME (dotpag, bakpag) < 0) - pag2_errno = errno; - /* mv modules.db .#modules.db */ - if (CVS_RENAME (dotdb, bakdb) < 0) - db2_errno = errno; - - /* mv "temp".dir modules.dir */ - if (CVS_RENAME (newdir, dotdir) < 0) - dir3_errno = errno; - /* mv "temp".pag modules.pag */ - if (CVS_RENAME (newpag, dotpag) < 0) - pag3_errno = errno; - /* mv "temp".db modules.db */ - if (CVS_RENAME (newdb, dotdb) < 0) - db3_errno = errno; - - /* OK -- make my day */ - SIG_endCrSect (); - - /* I didn't want to call error() when we had signals blocked - (unnecessary?), but do it now. */ - if (dir1_errno && !existence_error (dir1_errno)) - error (0, dir1_errno, "cannot remove %s", bakdir); - if (pag1_errno && !existence_error (pag1_errno)) - error (0, pag1_errno, "cannot remove %s", bakpag); - if (db1_errno && !existence_error (db1_errno)) - error (0, db1_errno, "cannot remove %s", bakdb); - - if (dir2_errno && !existence_error (dir2_errno)) - error (0, dir2_errno, "cannot remove %s", bakdir); - if (pag2_errno && !existence_error (pag2_errno)) - error (0, pag2_errno, "cannot remove %s", bakpag); - if (db2_errno && !existence_error (db2_errno)) - error (0, db2_errno, "cannot remove %s", bakdb); - - if (dir3_errno && !existence_error (dir3_errno)) - error (0, dir3_errno, "cannot remove %s", bakdir); - if (pag3_errno && !existence_error (pag3_errno)) - error (0, pag3_errno, "cannot remove %s", bakpag); - if (db3_errno && !existence_error (db3_errno)) - error (0, db3_errno, "cannot remove %s", bakdb); -} - -#endif /* !MY_NDBM */ - -static void -rename_rcsfile (temp, real) - char *temp; - char *real; -{ - char *bak; - struct stat statbuf; - char *rcs; - - /* Set "x" bits if set in original. */ - rcs = xmalloc (strlen (real) + sizeof (RCSEXT) + 10); - (void) sprintf (rcs, "%s%s", real, RCSEXT); - statbuf.st_mode = 0; /* in case rcs file doesn't exist, but it should... */ - if (CVS_STAT (rcs, &statbuf) < 0 - && !existence_error (errno)) - error (0, errno, "cannot stat %s", rcs); - free (rcs); - - if (chmod (temp, 0444 | (statbuf.st_mode & 0111)) < 0) - error (0, errno, "warning: cannot chmod %s", temp); - bak = xmalloc (strlen (real) + sizeof (BAKPREFIX) + 10); - (void) sprintf (bak, "%s%s", BAKPREFIX, real); - - /* rm .#loginfo */ - if (unlink_file (bak) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", bak); - - /* mv loginfo .#loginfo */ - if (CVS_RENAME (real, bak) < 0 - && !existence_error (errno)) - error (0, errno, "cannot rename %s to %s", real, bak); - - /* mv "temp" loginfo */ - if (CVS_RENAME (temp, real) < 0 - && !existence_error (errno)) - error (0, errno, "cannot rename %s to %s", temp, real); - - free (bak); -} - -/* - * Walk PATH backwards to the root directory looking for the root of a - * repository. - */ -static char * -in_repository (const char *path) -{ - char *cp = xstrdup (path); - - for (;;) - { - if (isdir (cp)) - { - int foundit; - char *adm = xmalloc (strlen(cp) + strlen(CVSROOTADM) + 2); - sprintf (adm, "%s/%s", cp, CVSROOTADM); - foundit = isdir (adm); - free (adm); - if (foundit) return cp; - } - - /* If last_component() returns the empty string, then cp either - * points at the system root or is the empty string itself. - */ - if (!*last_component (cp) || !strcmp (cp, ".") - || last_component(cp) == cp) - break; - - cp[strlen(cp) - strlen(last_component(cp)) - 1] = '\0'; - } - - return NULL; -} - - -const char *const init_usage[] = { - "Usage: %s %s\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -int -init (argc, argv) - int argc; - char **argv; -{ - /* Name of CVSROOT directory. */ - char *adm; - /* Name of this administrative file. */ - char *info; - /* Name of ,v file for this administrative file. */ - char *info_v; - /* Exit status. */ - int err = 0; - - char *root_dir; - const struct admin_file *fileptr; - - assert (!server_active); - - umask (cvsumask); - - if (argc == -1 || argc > 1) - usage (init_usage); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - start_server (); - - ign_setup (); - send_init_command (); - return get_responses_and_close (); - } -#endif /* CLIENT_SUPPORT */ - - root_dir = in_repository (current_parsed_root->directory); - - if (root_dir && strcmp (root_dir, current_parsed_root->directory)) - error (1, 0, - "Cannot initialize repository under existing CVSROOT: `%s'", - root_dir); - free (root_dir); - - /* Note: we do *not* create parent directories as needed like the - old cvsinit.sh script did. Few utilities do that, and a - non-existent parent directory is as likely to be a typo as something - which needs to be created. */ - mkdir_if_needed (current_parsed_root->directory); - - adm = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) + 2); - sprintf (adm, "%s/%s", current_parsed_root->directory, CVSROOTADM); - mkdir_if_needed (adm); - - /* This is needed because we pass "fileptr->filename" not "info" - to add_rcs_file below. I think this would be easy to change, - thus nuking the need for CVS_CHDIR here, but I haven't looked - closely (e.g. see wrappers calls within add_rcs_file). */ - 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); - info_v = xmalloc (strlen (adm) + 80); - for (fileptr = filelist; fileptr && fileptr->filename; ++fileptr) - { - if (fileptr->contents == NULL) - continue; - strcpy (info, adm); - strcat (info, "/"); - strcat (info, fileptr->filename); - strcpy (info_v, info); - strcat (info_v, RCSEXT); - if (isfile (info_v)) - /* We will check out this file in the mkmodules step. - Nothing else is required. */ - ; - else - { - int retcode; - - if (!isfile (info)) - { - FILE *fp; - const char * const *p; - - fp = open_file (info, "w"); - for (p = fileptr->contents; *p != NULL; ++p) - if (fputs (*p, fp) < 0) - error (1, errno, "cannot write %s", info); - if (fclose (fp) < 0) - error (1, errno, "cannot close %s", info); - } - /* The message used to say " of " and fileptr->filename after - "initial checkin" but I fail to see the point as we know what - file it is from the name. */ - retcode = add_rcs_file ("initial checkin", info_v, - fileptr->filename, "1.1", NULL, - - /* No vendor branch. */ - NULL, NULL, 0, NULL, - - NULL, 0, NULL); - if (retcode != 0) - /* add_rcs_file already printed an error message. */ - err = 1; - } - } - - /* Turn on history logging by default. The user can remove the file - to disable it. */ - strcpy (info, adm); - strcat (info, "/"); - strcat (info, CVSROOTADM_HISTORY); - if (!isfile (info)) - { - FILE *fp; - - 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); - free (info_v); - - mkmodules (adm); - - free (adm); - return err; -} diff --git a/contrib/cvs/src/modules.c b/contrib/cvs/src/modules.c deleted file mode 100644 index 5cbc2ec..0000000 --- a/contrib/cvs/src/modules.c +++ /dev/null @@ -1,1101 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License - * as specified in the README file that comes with the CVS source - * distribution. - * - * Modules - * - * Functions for accessing the modules file. - * - * The modules file supports basically three formats of lines: - * key [options] directory files... [ -x directory [files] ] ... - * key [options] directory [ -x directory [files] ] ... - * key -a aliases... - * - * The -a option allows an aliasing step in the parsing of the modules - * file. The "aliases" listed on a line following the -a are - * processed one-by-one, as if they were specified as arguments on the - * command line. - */ - -#include <assert.h> -#include "cvs.h" -#include "savecwd.h" - - -/* Defines related to the syntax of the modules file. */ - -/* Options in modules file. Note that it is OK to use GNU getopt features; - we already are arranging to make sure we are using the getopt distributed - with CVS. */ -#define CVSMODULE_OPTS "+ad:lo:e:s:t:" - -/* Special delimiter. */ -#define CVSMODULE_SPEC '&' - -struct sortrec -{ - /* Name of the module, malloc'd. */ - char *modname; - /* If Status variable is set, this is either def_status or the malloc'd - name of the status. If Status is not set, the field is left - uninitialized. */ - char *status; - /* Pointer to a malloc'd array which contains (1) the raw contents - of the options and arguments, excluding comments, (2) a '\0', - and (3) the storage for the "comment" field. */ - char *rest; - char *comment; -}; - -static int sort_order PROTO((const PTR l, const PTR r)); -static void save_d PROTO((char *k, int ks, char *d, int ds)); - - -/* - * Open the modules file, and die if the CVSROOT environment variable - * was not set. If the modules file does not exist, that's fine, and - * a warning message is displayed and a NULL is returned. - */ -DBM * -open_module () -{ - char *mfile; - DBM *retval; - - if (current_parsed_root == NULL) - { - error (0, 0, "must set the CVSROOT environment variable"); - error (1, 0, "or specify the '-d' global option"); - } - mfile = xmalloc (strlen (current_parsed_root->directory) - + sizeof (CVSROOTADM) - + sizeof (CVSROOTADM_MODULES) + 3); - (void) sprintf (mfile, "%s/%s/%s", current_parsed_root->directory, - CVSROOTADM, CVSROOTADM_MODULES); - retval = dbm_open (mfile, O_RDONLY, 0666); - free (mfile); - return retval; -} - -/* - * Close the modules file, if the open succeeded, that is - */ -void -close_module (db) - DBM *db; -{ - if (db != NULL) - dbm_close (db); -} - - - -/* - * This is the recursive function that processes a module name. - * It calls back the passed routine for each directory of a module - * It runs the post checkout or post tag proc from the modules file - */ -static int -my_module (db, mname, m_type, msg, callback_proc, where, shorten, - local_specified, run_module_prog, build_dirs, extra_arg, - stack) - DBM *db; - char *mname; - enum mtype m_type; - char *msg; - CALLBACKPROC callback_proc; - char *where; - int shorten; - int local_specified; - int run_module_prog; - int build_dirs; - char *extra_arg; - List *stack; -{ - char *checkout_prog = NULL; - char *export_prog = NULL; - char *tag_prog = NULL; - struct saved_cwd cwd; - int cwd_saved = 0; - char *line; - int modargc; - int xmodargc; - char **modargv = NULL; - char **xmodargv = NULL; - /* Found entry from modules file, including options and such. */ - char *value = NULL; - char *mwhere = NULL; - char *mfile = NULL; - char *spec_opt = NULL; - int alias = 0; - datum key, val; - char *cp; - int c, err = 0; - int nonalias_opt = 0; - -#ifdef SERVER_SUPPORT - int restore_server_dir = 0; - char *server_dir_to_restore = NULL; - if (trace) - { - char *buf; - - /* We use cvs_outerr, rather than fprintf to stderr, because - this may be called by server code with error_use_protocol - set. */ - buf = xmalloc (100 - + strlen (mname) - + strlen (msg) - + (where ? strlen (where) : 0) - + (extra_arg ? strlen (extra_arg) : 0)); - sprintf (buf, "%s-> my_module (%s, %s, %s, %s)\n", - CLIENT_SERVER_STR, - mname, msg, where ? where : "", - extra_arg ? extra_arg : ""); - cvs_outerr (buf, 0); - free (buf); - } -#endif - - /* Don't process absolute directories. Anything else could be a security - * problem. Before this check was put in place: - * - * $ cvs -d:fork:/cvsroot co /foo - * cvs server: warning: cannot make directory CVS in /: Permission denied - * cvs [server aborted]: cannot make directory /foo: Permission denied - * $ - */ - if (isabsolute (mname)) - error (1, 0, "Absolute module reference invalid: `%s'", mname); - - /* Similarly for directories that attempt to step above the root of the - * repository. - */ - if (pathname_levels (mname) > 0) - error (1, 0, "up-level in module reference (`..') invalid: `%s'.", - mname); - - /* if this is a directory to ignore, add it to that list */ - if (mname[0] == '!' && mname[1] != '\0') - { - ign_dir_add (mname+1); - goto do_module_return; - } - - /* strip extra stuff from the module name */ - strip_trailing_slashes (mname); - - /* - * Look up the module using the following scheme: - * 1) look for mname as a module name - * 2) look for mname as a directory - * 3) look for mname as a file - * 4) take mname up to the first slash and look it up as a module name - * (this is for checking out only part of a module) - */ - - /* look it up as a module name */ - key.dptr = mname; - key.dsize = strlen (key.dptr); - if (db != NULL) - val = dbm_fetch (db, key); - else - val.dptr = NULL; - if (val.dptr != NULL) - { - /* 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 (value, '#')) != NULL) - *cp = '\0'; - else - cp = value + val.dsize; - - /* Always strip trailing spaces */ - while (cp > value && isspace ((unsigned char) *--cp)) - *cp = '\0'; - - mwhere = xstrdup (mname); - goto found; - } - else - { - char *file; - char *attic_file; - char *acp; - int is_found = 0; - - /* check to see if mname is a directory or file */ - file = xmalloc (strlen (current_parsed_root->directory) - + strlen (mname) + sizeof(RCSEXT) + 2); - (void) sprintf (file, "%s/%s", current_parsed_root->directory, mname); - attic_file = xmalloc (strlen (current_parsed_root->directory) - + strlen (mname) - + sizeof (CVSATTIC) + sizeof (RCSEXT) + 3); - if ((acp = strrchr (mname, '/')) != NULL) - { - *acp = '\0'; - (void) sprintf (attic_file, "%s/%s/%s/%s%s", current_parsed_root->directory, - mname, CVSATTIC, acp + 1, RCSEXT); - *acp = '/'; - } - else - (void) sprintf (attic_file, "%s/%s/%s%s", - current_parsed_root->directory, - CVSATTIC, mname, RCSEXT); - - if (isdir (file)) - { - modargv = xmalloc (sizeof (*modargv)); - modargv[0] = xstrdup (mname); - modargc = 1; - is_found = 1; - } - else - { - (void) strcat (file, RCSEXT); - if (isfile (file) || isfile (attic_file)) - { - /* if mname was a file, we have to split it into "dir file" */ - if ((cp = strrchr (mname, '/')) != NULL && cp != mname) - { - modargv = xmalloc (2 * sizeof (*modargv)); - modargv[0] = xmalloc (strlen (mname) + 2); - strncpy (modargv[0], mname, cp - mname); - modargv[0][cp - mname] = '\0'; - modargv[1] = xstrdup (cp + 1); - modargc = 2; - } - else - { - /* - * the only '/' at the beginning or no '/' at all - * means the file we are interested in is in CVSROOT - * itself so the directory should be '.' - */ - if (cp == mname) - { - /* drop the leading / if specified */ - modargv = xmalloc (2 * sizeof (*modargv)); - modargv[0] = xstrdup ("."); - modargv[1] = xstrdup (mname + 1); - modargc = 2; - } - else - { - /* otherwise just copy it */ - modargv = xmalloc (2 * sizeof (*modargv)); - modargv[0] = xstrdup ("."); - modargv[1] = xstrdup (mname); - modargc = 2; - } - } - is_found = 1; - } - } - free (attic_file); - free (file); - - if (is_found) - { - assert (value == NULL); - - /* OK, we have now set up modargv with the actual - file/directory we want to work on. We duplicate a - small amount of code here because the vast majority of - the code after the "found" label does not pertain to - the case where we found a file/directory rather than - finding an entry in the modules file. */ - if (save_cwd (&cwd)) - error_exit (); - cwd_saved = 1; - - err += callback_proc (modargc, modargv, where, mwhere, mfile, - shorten, - local_specified, mname, msg); - - free_names (&modargc, modargv); - - /* cd back to where we started. */ - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - cwd_saved = 0; - - goto do_module_return; - } - } - - /* look up everything to the first / as a module */ - if (mname[0] != '/' && (cp = strchr (mname, '/')) != NULL) - { - /* Make the slash the new end of the string temporarily */ - *cp = '\0'; - key.dptr = mname; - key.dsize = strlen (key.dptr); - - /* do the lookup */ - if (db != NULL) - val = dbm_fetch (db, key); - else - val.dptr = NULL; - - /* if we found it, clean up the value and life is good */ - if (val.dptr != NULL) - { - char *cp2; - - /* 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 (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); - mfile = cp + 1; - assert (strlen (mfile)); - - /* put the / back in mname */ - *cp = '/'; - - goto found; - } - - /* put the / back in mname */ - *cp = '/'; - } - - /* if we got here, we couldn't find it using our search, so give up */ - error (0, 0, "cannot find module `%s' - ignored", mname); - err++; - goto do_module_return; - - - /* - * At this point, we found what we were looking for in one - * of the many different forms. - */ - found: - - /* remember where we start */ - if (save_cwd (&cwd)) - error_exit (); - cwd_saved = 1; - - assert (value != NULL); - - /* search the value for the special delimiter and save for later */ - if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL) - { - *cp = '\0'; /* null out the special char */ - spec_opt = cp + 1; /* save the options for later */ - - /* 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 */ - if (mfile != NULL) - spec_opt = NULL; - - /* - * value now contains one of the following: - * 1) dir - * 2) dir file - * 3) the value from modules without any special args - * [ args ] dir [file] [file] ... - * or -a module [ module ] ... - */ - - /* Put the value on a line with XXX prepended for getopt to eat */ - line = xmalloc (strlen (value) + 5); - strcpy(line, "XXX "); - strcpy(line + 4, value); - - /* turn the line into an argv[] array */ - line2argv (&xmodargc, &xmodargv, line, " \t"); - free (line); - modargc = xmodargc; - modargv = xmodargv; - - /* parse the args */ - optind = 0; - while ((c = getopt (modargc, modargv, CVSMODULE_OPTS)) != -1) - { - switch (c) - { - case 'a': - alias = 1; - break; - case 'd': - if (mwhere) - free (mwhere); - mwhere = xstrdup (optarg); - nonalias_opt = 1; - break; - case 'l': - local_specified = 1; - nonalias_opt = 1; - break; - case 'o': - if (checkout_prog) - free (checkout_prog); - checkout_prog = xstrdup (optarg); - nonalias_opt = 1; - break; - case 'e': - if (export_prog) - free (export_prog); - export_prog = xstrdup (optarg); - nonalias_opt = 1; - break; - case 't': - if (tag_prog) - free (tag_prog); - tag_prog = xstrdup (optarg); - nonalias_opt = 1; - break; - case '?': - error (0, 0, - "modules file has invalid option for key %s value %s", - key.dptr, value); - err++; - goto do_module_return; - } - } - modargc -= optind; - modargv += optind; - if (modargc == 0 && spec_opt == NULL) - { - error (0, 0, "modules file missing directory for module %s", mname); - ++err; - goto do_module_return; - } - - if (alias && nonalias_opt) - { - /* The documentation has never said it is legal to specify - -a along with another option. And I believe that in the past - CVS has ignored the options other than -a, more or less, in this - situation. */ - error (0, 0, "\ --a cannot be specified in the modules file along with other options"); - ++err; - goto do_module_return; - } - - /* if this was an alias, call ourselves recursively for each module */ - if (alias) - { - int i; - - for (i = 0; i < modargc; i++) - { - /* - * Recursion check: if an alias module calls itself or a module - * which causes the first to be called again, print an error - * message and stop recursing. - * - * Algorithm: - * - * 1. Check that MNAME isn't in the stack. - * 2. Push MNAME onto the stack. - * 3. Call do_module(). - * 4. Pop MNAME from the stack. - */ - if (stack && findnode (stack, mname)) - error (0, 0, - "module `%s' in modules file contains infinite loop", - mname); - else - { - if (!stack) stack = getlist(); - push_string (stack, mname); - err += my_module (db, modargv[i], m_type, msg, callback_proc, - where, shorten, local_specified, - run_module_prog, build_dirs, extra_arg, - stack); - pop_string (stack); - if (isempty (stack)) dellist (&stack); - } - } - goto do_module_return; - } - - if (mfile != NULL && modargc > 1) - { - error (0, 0, "\ -module `%s' is a request for a file in a module which is not a directory", - mname); - ++err; - goto do_module_return; - } - - /* otherwise, process this module */ - 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; - - if (!build_dirs) - goto do_special; - - 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; - -#ifdef SERVER_SUPPORT - /* We want to check out into the directory named by the module. - So we set a global variable which tells the server to glom that - directory name onto the front. A cleaner approach would be some - way of passing it down to the recursive call, through the - callback_proc, to start_recursion, and then into the update_dir in - the struct file_info. That way the "Updating foo" message could - print the actual directory we are checking out into. - - For local CVS, this is handled by the chdir call above - (directly or via the callback_proc). */ - if (server_active && spec_opt != NULL) - { - char *change_to; - - change_to = where ? where : (mwhere ? mwhere : mname); - server_dir_to_restore = server_dir; - restore_server_dir = 1; - server_dir = - xmalloc ((server_dir_to_restore != NULL - ? strlen (server_dir_to_restore) - : 0) - + strlen (change_to) - + 5); - server_dir[0] = '\0'; - if (server_dir_to_restore != NULL) - { - strcat (server_dir, server_dir_to_restore); - strcat (server_dir, "/"); - } - strcat (server_dir, change_to); - } -#endif - - while (spec_opt != NULL) - { - char *next_opt; - - cp = strchr (spec_opt, CVSMODULE_SPEC); - if (cp != NULL) - { - /* save the beginning of the next arg */ - next_opt = cp + 1; - - /* strip whitespace off the end */ - do - *cp = '\0'; - while (cp > spec_opt && isspace ((unsigned char) *--cp)); - } - else - next_opt = NULL; - - /* strip whitespace from front */ - while (isspace ((unsigned char) *spec_opt)) - spec_opt++; - - if (*spec_opt == '\0') - error (0, 0, "Mal-formed %c option for module %s - ignored", - CVSMODULE_SPEC, mname); - else - err += my_module (db, spec_opt, m_type, msg, callback_proc, - (char *) NULL, 0, local_specified, - run_module_prog, build_dirs, extra_arg, - stack); - spec_opt = next_opt; - } - -#ifdef SERVER_SUPPORT - if (server_active && restore_server_dir) - { - free (server_dir); - server_dir = server_dir_to_restore; - } -#endif - - /* cd back to where we started */ - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - cwd_saved = 0; - - /* run checkout or tag prog if appropriate */ - if (err == 0 && run_module_prog) - { - if ((m_type == TAG && tag_prog != NULL) || - (m_type == CHECKOUT && checkout_prog != NULL) || - (m_type == EXPORT && export_prog != NULL)) - { - /* - * If a relative pathname is specified as the checkout, tag - * or export proc, try to tack on the current "where" value. - * if we can't find a matching program, just punt and use - * whatever is specified in the modules file. - */ - char *real_prog = NULL; - char *prog = (m_type == TAG ? tag_prog : - (m_type == CHECKOUT ? checkout_prog : export_prog)); - char *real_where = (where != NULL ? where : mwhere); - char *expanded_path; - - if ((*prog != '/') && (*prog != '.')) - { - real_prog = xmalloc (strlen (real_where) + strlen (prog) - + 10); - (void) sprintf (real_prog, "%s/%s", real_where, prog); - if (isfile (real_prog)) - prog = real_prog; - } - - /* XXX can we determine the line number for this entry??? */ - expanded_path = expand_path (prog, "modules", 0); - if (expanded_path != NULL) - { - run_setup (expanded_path); - run_arg (real_where); - - if (extra_arg) - run_arg (extra_arg); - - if (!quiet) - { - cvs_output (program_name, 0); - cvs_output (" ", 1); - cvs_output (cvs_cmd_name, 0); - 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); - } - if (real_prog) free (real_prog); - } - } - - do_module_return: - /* clean up */ - if (xmodargv != NULL) - free_names (&xmodargc, xmodargv); - if (mwhere) - free (mwhere); - if (checkout_prog) - free (checkout_prog); - if (export_prog) - free (export_prog); - if (tag_prog) - free (tag_prog); - if (cwd_saved) - free_cwd (&cwd); - if (value != NULL) - free (value); - - return (err); -} - - - -/* External face of do_module so that we can have an internal version which - * accepts a stack argument to track alias recursion. - */ -int -do_module (db, mname, m_type, msg, callback_proc, where, shorten, - local_specified, run_module_prog, build_dirs, extra_arg) - DBM *db; - char *mname; - enum mtype m_type; - char *msg; - CALLBACKPROC callback_proc; - char *where; - int shorten; - int local_specified; - int run_module_prog; - int build_dirs; - char *extra_arg; -{ - return my_module (db, mname, m_type, msg, callback_proc, where, shorten, - local_specified, run_module_prog, build_dirs, extra_arg, - NULL); -} - - - -/* - Read all the records from the modules database into an array. - - Sort the array depending on what format is desired. - - Print the array in the format desired. - - Currently, there are only two "desires": - - 1. Sort by module name and format the whole entry including switches, - files and the comment field: (Including aliases) - - modulename -s switches, one per line, even if - it has many switches. - Directories and files involved, formatted - to cover multiple lines if necessary. - # Comment, also formatted to cover multiple - # lines if necessary. - - 2. Sort by status field string and print: (*not* including aliases) - - modulename STATUS Directories and files involved, formatted - to cover multiple lines if necessary. - # Comment, also formatted to cover multiple - # lines if necessary. -*/ - -static struct sortrec *s_head; - -static int s_max = 0; /* Number of elements allocated */ -static int s_count = 0; /* Number of elements used */ - -static int Status; /* Nonzero if the user is - interested in status - information as well as - module name */ -static char def_status[] = "NONE"; - -/* Sort routine for qsort: - - If we want the "Status" field to be sorted, check it first. - - Then compare the "module name" fields. Since they are unique, we don't - have to look further. -*/ -static int -sort_order (l, r) - const PTR l; - const PTR r; -{ - int i; - const struct sortrec *left = (const struct sortrec *) l; - const struct sortrec *right = (const struct sortrec *) r; - - if (Status) - { - /* If Sort by status field, compare them. */ - if ((i = strcmp (left->status, right->status)) != 0) - return (i); - } - return (strcmp (left->modname, right->modname)); -} - -static void -save_d (k, ks, d, ds) - char *k; - int ks; - char *d; - int ds; -{ - char *cp, *cp2; - struct sortrec *s_rec; - - if (Status && *d == '-' && *(d + 1) == 'a') - return; /* We want "cvs co -s" and it is an alias! */ - - if (s_count == s_max) - { - s_max += 64; - s_head = (struct sortrec *) xrealloc ((char *) s_head, s_max * sizeof (*s_head)); - } - s_rec = &s_head[s_count]; - s_rec->modname = cp = xmalloc (ks + 1); - (void) strncpy (cp, k, ks); - *(cp + ks) = '\0'; - - s_rec->rest = cp2 = xmalloc (ds + 1); - cp = d; - *(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */ - - while (isspace ((unsigned char) *cp)) - cp++; - /* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */ - while (*cp) - { - if (isspace ((unsigned char) *cp)) - { - *cp2++ = ' '; - while (isspace ((unsigned char) *cp)) - cp++; - } - else - *cp2++ = *cp++; - } - *cp2 = '\0'; - - /* Look for the "-s statusvalue" text */ - if (Status) - { - s_rec->status = def_status; - - for (cp = s_rec->rest; (cp2 = strchr (cp, '-')) != NULL; cp = ++cp2) - { - if (*(cp2 + 1) == 's' && *(cp2 + 2) == ' ') - { - char *status_start; - - cp2 += 3; - status_start = cp2; - while (*cp2 != ' ' && *cp2 != '\0') - cp2++; - s_rec->status = xmalloc (cp2 - status_start + 1); - strncpy (s_rec->status, status_start, cp2 - status_start); - s_rec->status[cp2 - status_start] = '\0'; - cp = cp2; - break; - } - } - } - else - cp = s_rec->rest; - - /* Find comment field, clean up on all three sides & compress blanks */ - if ((cp2 = cp = strchr (cp, '#')) != NULL) - { - if (*--cp2 == ' ') - *cp2 = '\0'; - if (*++cp == ' ') - cp++; - s_rec->comment = cp; - } - else - s_rec->comment = ""; - - s_count++; -} - -/* Print out the module database as we know it. If STATUS is - non-zero, print out status information for each module. */ - -void -cat_module (status) - int status; -{ - DBM *db; - datum key, val; - int i, c, wid, argc, cols = 80, indent, fill; - int moduleargc; - struct sortrec *s_h; - char *cp, *cp2, **argv; - char **moduleargv; - - Status = status; - - /* Read the whole modules file into allocated records */ - if (!(db = open_module ())) - error (1, 0, "failed to open the modules file"); - - for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_nextkey (db)) - { - val = dbm_fetch (db, key); - if (val.dptr != NULL) - save_d (key.dptr, key.dsize, val.dptr, val.dsize); - } - - close_module (db); - - /* Sort the list as requested */ - qsort ((PTR) s_head, s_count, sizeof (struct sortrec), sort_order); - - /* - * Run through the sorted array and format the entries - * indent = space for modulename + space for status field - */ - indent = 12 + (status * 12); - fill = cols - (indent + 2); - for (s_h = s_head, i = 0; i < s_count; i++, s_h++) - { - char *line; - - /* Print module name (and status, if wanted) */ - line = xmalloc (strlen (s_h->modname) + 15); - sprintf (line, "%-12s", s_h->modname); - cvs_output (line, 0); - free (line); - if (status) - { - line = xmalloc (strlen (s_h->status) + 15); - sprintf (line, " %-11s", s_h->status); - cvs_output (line, 0); - free (line); - } - - line = xmalloc (strlen (s_h->modname) + strlen (s_h->rest) + 15); - /* Parse module file entry as command line and print options */ - (void) sprintf (line, "%s %s", s_h->modname, s_h->rest); - line2argv (&moduleargc, &moduleargv, line, " \t"); - free (line); - argc = moduleargc; - argv = moduleargv; - - optind = 0; - wid = 0; - while ((c = getopt (argc, argv, CVSMODULE_OPTS)) != -1) - { - if (!status) - { - if (c == 'a' || c == 'l') - { - char buf[5]; - - sprintf (buf, " -%c", c); - cvs_output (buf, 0); - wid += 3; /* Could just set it to 3 */ - } - else - { - char buf[10]; - - if (strlen (optarg) + 4 + wid > (unsigned) fill) - { - int j; - - cvs_output ("\n", 1); - for (j = 0; j < indent; ++j) - cvs_output (" ", 1); - wid = 0; - } - sprintf (buf, " -%c ", c); - cvs_output (buf, 0); - cvs_output (optarg, 0); - wid += strlen (optarg) + 4; - } - } - } - argc -= optind; - argv += optind; - - /* Format and Print all the files and directories */ - for (; argc--; argv++) - { - if (strlen (*argv) + wid > (unsigned) fill) - { - int j; - - cvs_output ("\n", 1); - for (j = 0; j < indent; ++j) - cvs_output (" ", 1); - wid = 0; - } - cvs_output (" ", 1); - cvs_output (*argv, 0); - wid += strlen (*argv) + 1; - } - cvs_output ("\n", 1); - - /* Format the comment field -- save_d (), compressed spaces */ - for (cp2 = cp = s_h->comment; *cp; cp2 = cp) - { - int j; - - for (j = 0; j < indent; ++j) - cvs_output (" ", 1); - cvs_output (" # ", 0); - if (strlen (cp2) < (unsigned) (fill - 2)) - { - cvs_output (cp2, 0); - cvs_output ("\n", 1); - break; - } - cp += fill - 2; - while (*cp != ' ' && cp > cp2) - cp--; - if (cp == cp2) - { - cvs_output (cp2, 0); - cvs_output ("\n", 1); - break; - } - - *cp++ = '\0'; - cvs_output (cp2, 0); - cvs_output ("\n", 1); - } - - free_names(&moduleargc, moduleargv); - /* FIXME-leak: here is where we would free s_h->modname, s_h->rest, - and if applicable, s_h->status. Not exactly a memory leak, - in the sense that we are about to exit(), but may be worth - noting if we ever do a multithreaded server or something of - the sort. */ - } - /* FIXME-leak: as above, here is where we would free s_head. */ -} diff --git a/contrib/cvs/src/myndbm.c b/contrib/cvs/src/myndbm.c deleted file mode 100644 index cb99cc2..0000000 --- a/contrib/cvs/src/myndbm.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * A simple ndbm-emulator for CVS. It parses a text file of the format: - * - * key value - * - * at dbm_open time, and loads the entire file into memory. As such, it is - * probably only good for fairly small modules files. Ours is about 30K in - * size, and this code works fine. - */ - -#include <assert.h> -#include "cvs.h" -#include "getline.h" - -#ifdef MY_NDBM -# ifndef O_ACCMODE -# define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) -# endif /* defined O_ACCMODE */ - -static void mydbm_load_file PROTO ((FILE *, List *, char *)); - -/* Returns NULL on error in which case errno has been set to indicate - the error. Can also call error() itself. */ -/* ARGSUSED */ -DBM * -mydbm_open (file, flags, mode) - char *file; - int flags; - int mode; -{ - FILE *fp; - DBM *db; - - fp = CVS_FOPEN (file, (flags & O_ACCMODE) != O_RDONLY ? - FOPEN_BINARY_READWRITE : FOPEN_BINARY_READ); - if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT))) - return ((DBM *) 0); - - db = (DBM *) xmalloc (sizeof (*db)); - db->dbm_list = getlist (); - db->modified = 0; - db->name = xstrdup (file); - - if (fp != NULL) - { - mydbm_load_file (fp, db->dbm_list, file); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", file); - } - return (db); -} - -static int write_item PROTO ((Node *, void *)); - -static int -write_item (node, data) - Node *node; - void *data; -{ - FILE *fp = (FILE *)data; - fputs (node->key, fp); - fputs (" ", fp); - fputs (node->data, fp); - fputs ("\012", fp); - return 0; -} - -void -mydbm_close (db) - DBM *db; -{ - if (db->modified) - { - FILE *fp; - fp = CVS_FOPEN (db->name, FOPEN_BINARY_WRITE); - if (fp == NULL) - error (1, errno, "cannot write %s", db->name); - walklist (db->dbm_list, write_item, (void *)fp); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", db->name); - } - free (db->name); - dellist (&db->dbm_list); - free ((char *) db); -} - -datum -mydbm_fetch (db, key) - DBM *db; - datum key; -{ - Node *p; - char *s; - datum val; - - /* make sure it's null-terminated */ - s = xmalloc (key.dsize + 1); - (void) strncpy (s, key.dptr, key.dsize); - s[key.dsize] = '\0'; - - p = findnode (db->dbm_list, s); - if (p) - { - val.dptr = p->data; - val.dsize = strlen (p->data); - } - else - { - val.dptr = (char *) NULL; - val.dsize = 0; - } - free (s); - return (val); -} - -datum -mydbm_firstkey (db) - DBM *db; -{ - Node *head, *p; - datum key; - - head = db->dbm_list->list; - p = head->next; - if (p != head) - { - key.dptr = p->key; - key.dsize = strlen (p->key); - } - else - { - key.dptr = (char *) NULL; - key.dsize = 0; - } - db->dbm_next = p->next; - return (key); -} - -datum -mydbm_nextkey (db) - DBM *db; -{ - Node *head, *p; - datum key; - - head = db->dbm_list->list; - p = db->dbm_next; - if (p != head) - { - key.dptr = p->key; - key.dsize = strlen (p->key); - } - else - { - key.dptr = (char *) NULL; - key.dsize = 0; - } - db->dbm_next = p->next; - return (key); -} - -/* Note: only updates the in-memory copy, which is written out at - mydbm_close time. Note: Also differs from DBM in that on duplication, - it gives a warning, rather than either DBM_INSERT or DBM_REPLACE - behavior. */ -int -mydbm_store (db, key, value, flags) - DBM *db; - datum key; - datum value; - int flags; -{ - Node *node; - - node = getnode (); - node->type = NDBMNODE; - - node->key = xmalloc (key.dsize + 1); - *node->key = '\0'; - strncat (node->key, key.dptr, key.dsize); - - node->data = xmalloc (value.dsize + 1); - *(char *)node->data = '\0'; - strncat (node->data, value.dptr, value.dsize); - - db->modified = 1; - if (addnode (db->dbm_list, node) == -1) - { - error (0, 0, "attempt to insert duplicate key `%s'", node->key); - freenode (node); - return 0; - } - return 0; -} - -static void -mydbm_load_file (fp, list, filename) - FILE *fp; - List *list; - char *filename; /* Used in error messages. */ -{ - char *line = NULL; - size_t line_size; - char *value; - size_t value_allocated; - char *cp, *vp; - int cont; - int line_length; - int line_num; - - value_allocated = 1; - value = xmalloc (value_allocated); - - cont = 0; - line_num=0; - while ((line_length = - getstr (&line, &line_size, fp, '\012', 0, GETLINE_NO_LIMIT)) >= 0) - { - line_num++; - if (line_length > 0 && line[line_length - 1] == '\012') - { - /* Strip the newline. */ - --line_length; - line[line_length] = '\0'; - } - if (line_length > 0 && line[line_length - 1] == '\015') - { - /* If the file (e.g. modules) was written on an NT box, it will - contain CRLF at the ends of lines. Strip them (we can't do - this by opening the file in text mode because we might be - running on unix). */ - --line_length; - line[line_length] = '\0'; - } - - /* - * Add the line to the value, at the end if this is a continuation - * line; otherwise at the beginning, but only after any trailing - * backslash is removed. - */ - if (!cont) - value[0] = '\0'; - - /* - * See if the line we read is a continuation line, and strip the - * backslash if so. - */ - if (line_length > 0) - cp = &line[line_length - 1]; - else - cp = line; - if (*cp == '\\') - { - cont = 1; - *cp = '\0'; - --line_length; - } - else - { - cont = 0; - } - expand_string (&value, - &value_allocated, - strlen (value) + line_length + 5); - strcat (value, line); - - if (value[0] == '#') - continue; /* comment line */ - vp = value; - while (*vp && isspace ((unsigned char) *vp)) - vp++; - if (*vp == '\0') - continue; /* empty line */ - - /* - * If this was not a continuation line, add the entry to the database - */ - if (!cont) - { - Node *p = getnode (); - char *kp; - - kp = vp; - while (*vp && !isspace ((unsigned char) *vp)) - vp++; - if (*vp) - *vp++ = '\0'; /* NULL terminate the key */ - p->type = NDBMNODE; - p->key = xstrdup (kp); - while (*vp && isspace ((unsigned char) *vp)) - vp++; /* skip whitespace to value */ - if (*vp == '\0') - { - if (!really_quiet) - error (0, 0, - "warning: NULL value for key `%s' at line %d of `%s'", - p->key, line_num, filename); - freenode (p); - continue; - } - p->data = xstrdup (vp); - if (addnode (list, p) == -1) - { - if (!really_quiet) - error (0, 0, - "duplicate key found for `%s' at line %d of `%s'", - p->key, line_num, filename); - freenode (p); - } - } - } - if (line_length < 0 && !feof (fp)) - /* FIXME: should give the name of the file. */ - error (0, errno, "cannot read file in mydbm_load_file"); - - free (line); - free (value); -} - -#endif /* MY_NDBM */ diff --git a/contrib/cvs/src/myndbm.h b/contrib/cvs/src/myndbm.h deleted file mode 100644 index de23519..0000000 --- a/contrib/cvs/src/myndbm.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 1994-2005 The Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifdef MY_NDBM - -#define DBLKSIZ 4096 - -typedef struct -{ - List *dbm_list; /* cached database */ - Node *dbm_next; /* next key to return for nextkey() */ - - /* Name of the file to write to if modified is set. malloc'd. */ - char *name; - - /* Nonzero if the database has been modified and dbm_close needs to - write it out to disk. */ - int modified; -} DBM; - -typedef struct -{ - char *dptr; - int dsize; -} datum; - -/* - * So as not to conflict with other dbm_open, etc., routines that may - * be included by someone's libc, all of my emulation routines are prefixed - * by "my" and we define the "standard" ones to be "my" ones here. - */ -#define dbm_open mydbm_open -#define dbm_close mydbm_close -#define dbm_fetch mydbm_fetch -#define dbm_firstkey mydbm_firstkey -#define dbm_nextkey mydbm_nextkey -#define dbm_store mydbm_store -#define DBM_INSERT 0 -#define DBM_REPLACE 1 - -DBM *mydbm_open PROTO((char *file, int flags, int mode)); -void mydbm_close PROTO((DBM * db)); -datum mydbm_fetch PROTO((DBM * db, datum key)); -datum mydbm_firstkey PROTO((DBM * db)); -datum mydbm_nextkey PROTO((DBM * db)); -extern int mydbm_store PROTO ((DBM *, datum, datum, int)); - -#endif /* MY_NDBM */ diff --git a/contrib/cvs/src/no_diff.c b/contrib/cvs/src/no_diff.c deleted file mode 100644 index 45847a1..0000000 --- a/contrib/cvs/src/no_diff.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * No Difference - * - * The user file looks modified judging from its time stamp; however it needn't - * be. No_Difference() finds out whether it is or not. If it is not, it - * updates the administration. - * - * returns 0 if no differences are found and non-zero otherwise - */ - -#include "cvs.h" -#include <assert.h> - -int -No_Difference (finfo, vers) - struct file_info *finfo; - Vers_TS *vers; -{ - Node *p; - int ret; - char *ts, *options; - int retcode = 0; - char *tocvsPath; - - /* If ts_user is "Is-modified", we can only conclude the files are - different (since we don't have the file's contents). */ - if (vers->ts_user != NULL - && strcmp (vers->ts_user, "Is-modified") == 0) - return -1; - - if (!vers->srcfile || !vers->srcfile->path) - return (-1); /* different since we couldn't tell */ - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - /* If special files are in use, then any mismatch of file metadata - information also means that the files should be considered different. */ - if (preserve_perms && special_file_mismatch (finfo, vers->vn_user, NULL)) - return 1; -#endif - - if (vers->entdata && vers->entdata->options) - options = xstrdup (vers->entdata->options); - else - options = xstrdup (""); - - tocvsPath = wrap_tocvs_process_file (finfo->file); - retcode = RCS_cmp_file( vers->srcfile, vers->vn_user, (char **)NULL, - (char *)NULL, options, - tocvsPath == NULL ? finfo->file : tocvsPath ); - if (retcode == 0) - { - /* no difference was found, so fix the entries file */ - ts = time_stamp (finfo->file); - Register (finfo->entries, finfo->file, - vers->vn_user ? vers->vn_user : vers->vn_rcs, ts, - options, vers->tag, vers->date, (char *) 0); -#ifdef SERVER_SUPPORT - if (server_active) - { - /* We need to update the entries line on the client side. */ - server_update_entries - (finfo->file, finfo->update_dir, finfo->repository, SERVER_UPDATED); - } -#endif - free (ts); - - /* update the entdata pointer in the vers_ts structure */ - p = findnode (finfo->entries, finfo->file); - assert (p); - vers->entdata = p->data; - - ret = 0; - } - else - ret = 1; /* files were really different */ - - if (tocvsPath) - { - /* Need to call unlink myself because the noexec variable - * has been set to 1. */ - if (trace) - (void) fprintf (stderr, "%s-> unlink (%s)\n", - CLIENT_SERVER_STR, tocvsPath); - if ( CVS_UNLINK (tocvsPath) < 0) - error (0, errno, "could not remove %s", tocvsPath); - } - - free (options); - return (ret); -} diff --git a/contrib/cvs/src/parseinfo.c b/contrib/cvs/src/parseinfo.c deleted file mode 100644 index bf1e095..0000000 --- a/contrib/cvs/src/parseinfo.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Copyright (C) 1986-2008 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * $FreeBSD$ - */ - -#include "cvs.h" -#include "getline.h" -#include <assert.h> -#include "history.h" - -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 matching "ALL", or if no lines match, the last line matching - * "DEFAULT". - * - * Return 0 for success, -1 if there was not an INFOFILE, and >0 for failure. - */ -int -Parse_Info (infofile, repository, callproc, all) - const char *infofile; - const char *repository; - CALLPROC callproc; - int all; -{ - int err = 0; - FILE *fp_info; - char *infopath; - char *line = NULL; - size_t line_allocated = 0; - char *default_value = NULL; - int default_line = 0; - char *expanded_value; - int callback_done, line_number; - char *cp, *exp, *value; - const char *srepos; - const char *regex_err; - - assert (repository); - - if (current_parsed_root == NULL) - { - /* XXX - should be error maybe? */ - error (0, 0, "CVSROOT variable not set"); - return (1); - } - - /* find the info file and open it */ - infopath = xmalloc (strlen (current_parsed_root->directory) - + strlen (infofile) - + sizeof (CVSROOTADM) - + 3); - (void) sprintf (infopath, "%s/%s/%s", current_parsed_root->directory, - CVSROOTADM, infofile); - fp_info = CVS_FOPEN (infopath, "r"); - if (fp_info == NULL) - { - /* If no file, don't do anything special. */ - if (!existence_error (errno)) - error (0, errno, "cannot open %s", infopath); - free (infopath); - return 0; - } - - /* strip off the CVSROOT if repository was absolute */ - srepos = Short_Repository (repository); - - if (trace) - (void) fprintf (stderr, "%s-> Parse_Info (%s, %s, %s)\n", -#ifdef SERVER_SUPPORT - server_active ? "S" : " ", -#else - "", -#endif - infopath, srepos, all ? "ALL" : "not ALL"); - - /* search the info file for lines that match */ - callback_done = line_number = 0; - while (getline (&line, &line_allocated, fp_info) >= 0) - { - line_number++; - - /* skip lines starting with # */ - if (line[0] == '#') - continue; - - /* skip whitespace at beginning of line */ - for (cp = line; *cp && isspace ((unsigned char) *cp); cp++) - ; - - /* if *cp is null, the whole line was blank */ - if (*cp == '\0') - continue; - - /* the regular expression is everything up to the first space */ - for (exp = cp; *cp && !isspace ((unsigned char) *cp); cp++) - ; - if (*cp != '\0') - *cp++ = '\0'; - - /* skip whitespace up to the start of the matching value */ - while (*cp && isspace ((unsigned char) *cp)) - cp++; - - /* no value to match with the regular expression is an error */ - if (*cp == '\0') - { - error (0, 0, "syntax error at line %d file %s; ignored", - line_number, infofile); - continue; - } - value = cp; - - /* strip the newline off the end of the value */ - if ((cp = strrchr (value, '\n')) != NULL) - *cp = '\0'; - - /* - * At this point, exp points to the regular expression, and value - * points to the value to call the callback routine with. Evaluate - * the regular expression against srepos and callback with the value - * if it matches. - */ - - /* save the default value so we have it later if we need it */ - if (strcmp (exp, "DEFAULT") == 0) - { - if (default_value != NULL) - { - error (0, 0, "Multiple `DEFAULT' lines (%d and %d) in %s file", - default_line, line_number, infofile); - free (default_value); - } - default_value = xstrdup(value); - default_line = line_number; - continue; - } - - /* - * For a regular expression of "ALL", do the callback always We may - * execute lots of ALL callbacks in addition to *one* regular matching - * callback or default - */ - if (strcmp (exp, "ALL") == 0) - { - if (!all) - error(0, 0, "Keyword `ALL' is ignored at line %d in %s file", - line_number, infofile); - else if ((expanded_value = expand_path (value, infofile, - line_number)) != NULL) - { - err += callproc (repository, expanded_value); - free (expanded_value); - } - else - err++; - continue; - } - - if (callback_done) - /* only first matching, plus "ALL"'s */ - continue; - - /* see if the repository matched this regular expression */ - if ((regex_err = re_comp (exp)) != NULL) - { - error (0, 0, "bad regular expression at line %d file %s: %s", - line_number, infofile, regex_err); - continue; - } - if (re_exec (srepos) == 0) - continue; /* no match */ - - /* it did, so do the callback and note that we did one */ - if ((expanded_value = expand_path (value, infofile, line_number)) != NULL) - { - err += callproc (repository, expanded_value); - free (expanded_value); - } - else - err++; - callback_done = 1; - } - if (ferror (fp_info)) - error (0, errno, "cannot read %s", infopath); - if (fclose (fp_info) < 0) - error (0, errno, "cannot close %s", infopath); - - /* if we fell through and didn't callback at all, do the default */ - if (callback_done == 0 && default_value != NULL) - { - if ((expanded_value = expand_path (default_value, infofile, default_line)) != NULL) - { - err += callproc (repository, expanded_value); - free (expanded_value); - } - else - err++; - } - - /* free up space if necessary */ - if (default_value != NULL) - free (default_value); - free (infopath); - if (line != NULL) - free (line); - - return (err); -} - - -/* Parse the CVS config file. The syntax right now is a bit ad hoc - but tries to draw on the best or more common features of the other - *info files and various unix (or non-unix) config file syntaxes. - Lines starting with # are comments. Settings are lines of the form - KEYWORD=VALUE. There is currently no way to have a multi-line - VALUE (would be nice if there was, probably). - - CVSROOT is the $CVSROOT directory - (current_parsed_root->directory might not be set yet, so this - function takes the cvsroot as a function argument). - - Returns 0 for success, negative value for failure. Call - error(0, ...) on errors in addition to the return value. */ -int -parse_config (cvsroot) - char *cvsroot; -{ - char *infopath; - FILE *fp_info; - char *line = NULL; - size_t line_allocated = 0; - size_t len; - char *p; - /* FIXME-reentrancy: If we do a multi-threaded server, this would need - to go to the per-connection data structures. */ - static int parsed = 0; - int ignore_unknown_config_keys = 0; - - /* Authentication code and serve_root might both want to call us. - Let this happen smoothly. */ - if (parsed) - return 0; - parsed = 1; - - infopath = xmalloc (strlen (cvsroot) - + sizeof (CVSROOTADM_CONFIG) - + sizeof (CVSROOTADM) - + 10); - if (infopath == NULL) - { - error (0, 0, "out of memory; cannot allocate infopath"); - goto error_return; - } - - strcpy (infopath, cvsroot); - strcat (infopath, "/"); - strcat (infopath, CVSROOTADM); - strcat (infopath, "/"); - strcat (infopath, CVSROOTADM_CONFIG); - - fp_info = CVS_FOPEN (infopath, "r"); - if (fp_info == NULL) - { - /* If no file, don't do anything special. */ - if (!existence_error (errno)) - { - /* Just a warning message; doesn't affect return - value, currently at least. */ - error (0, errno, "cannot open %s", infopath); - } - goto set_defaults_and_return; - } - - while (getline (&line, &line_allocated, fp_info) >= 0) - { - /* Skip comments. */ - if (line[0] == '#') - continue; - - /* At least for the moment we don't skip whitespace at the start - of the line. Too picky? Maybe. But being insufficiently - picky leads to all sorts of confusion, and it is a lot easier - to start out picky and relax it than the other way around. - - Is there any kind of written standard for the syntax of this - sort of config file? Anywhere in POSIX for example (I guess - makefiles are sort of close)? Red Hat Linux has a bunch of - these too (with some GUI tools which edit them)... - - Along the same lines, we might want a table of keywords, - with various types (boolean, string, &c), as a mechanism - for making sure the syntax is consistent. Any good examples - to follow there (Apache?)? */ - - /* Strip the trailing newline. There will be one unless we - read a partial line without a newline, and then got end of - file (or error?). */ - - len = strlen (line) - 1; - if (line[len] == '\n') - line[len] = '\0'; - - /* Skip blank lines. */ - if (line[0] == '\0') - continue; - - /* The first '=' separates keyword from value. */ - p = strchr (line, '='); - if (p == NULL) - { - /* Probably should be printing line number. */ - error (0, 0, "syntax error in %s: line '%s' is missing '='", - infopath, line); - goto error_return; - } - - *p++ = '\0'; - - if (strcmp (line, "RCSBIN") == 0) - { - /* This option used to specify the directory for RCS - executables. But since we don't run them any more, - this is a noop. Silently ignore it so that a - repository can work with either new or old CVS. */ - ; - } - else if (strcmp (line, "SystemAuth") == 0) - { - if (strcmp (p, "no") == 0) -#ifdef AUTH_SERVER_SUPPORT - system_auth = 0; -#else - /* Still parse the syntax but ignore the - option. That way the same config file can - be used for local and server. */ - ; -#endif - else if (strcmp (p, "yes") == 0) -#ifdef AUTH_SERVER_SUPPORT - system_auth = 1; -#else - ; -#endif - else - { - error (0, 0, "unrecognized value '%s' for SystemAuth", p); - goto error_return; - } - } - else if (strcmp (line, "tag") == 0) { - RCS_setlocalid(p); - } - else if (strcmp (line, "umask") == 0) { - cvsumask = (mode_t)(strtol(p, NULL, 8) & 0777); - } - else if (strcmp (line, "dlimit") == 0) { -#ifdef BSD -#include <sys/resource.h> - struct rlimit rl; - - if (getrlimit(RLIMIT_DATA, &rl) != -1) { - rl.rlim_cur = atoi(p); - rl.rlim_cur *= 1024; - - (void) setrlimit(RLIMIT_DATA, &rl); - } -#endif /* BSD */ - } - else if (strcmp (line, "PreservePermissions") == 0) - { - if (strcmp (p, "no") == 0) - preserve_perms = 0; - else if (strcmp (p, "yes") == 0) - { -#ifdef PRESERVE_PERMISSIONS_SUPPORT - preserve_perms = 1; -#else - error (0, 0, "\ -warning: this CVS does not support PreservePermissions"); -#endif - } - else - { - error (0, 0, "unrecognized value '%s' for PreservePermissions", - p); - goto error_return; - } - } - else if (strcmp (line, "TopLevelAdmin") == 0) - { - if (strcmp (p, "no") == 0) - top_level_admin = 0; - else if (strcmp (p, "yes") == 0) - top_level_admin = 1; - else - { - error (0, 0, "unrecognized value '%s' for TopLevelAdmin", p); - goto error_return; - } - } - else if (strcmp (line, "LockDir") == 0) - { - if (lock_dir != NULL) - free (lock_dir); - lock_dir = xstrdup (p); - /* Could try some validity checking, like whether we can - 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) - { - if (logHistory) free (logHistory); - logHistory = xstrdup (p); - } - } - else if (strcmp (line, "RereadLogAfterVerify") == 0) - { - if (strcmp (p, "no") == 0 || strcmp (p, "never") == 0) - RereadLogAfterVerify = LOGMSG_REREAD_NEVER; - else if (strcmp (p, "yes") == 0 || strcmp (p, "always") == 0) - RereadLogAfterVerify = LOGMSG_REREAD_ALWAYS; - else if (strcmp (p, "stat") == 0) - RereadLogAfterVerify = LOGMSG_REREAD_STAT; - } - else if (strcmp(line, "LocalKeyword") == 0) - { - /* Recognize cvs-1.12-style keyword control rather than erroring out. */ - RCS_setlocalid(p); - } - else if (strcmp(line, "KeywordExpand") == 0) - { - /* Recognize cvs-1.12-style keyword control rather than erroring out. */ - RCS_setincexc(p); - } - else if (strcmp (line, "IgnoreUnknownConfigKeys") == 0) - { - if (strcmp (p, "no") == 0 || strcmp (p, "false") == 0 - || strcmp (p, "off") == 0 || strcmp (p, "0") == 0) - ignore_unknown_config_keys = 0; - else if (strcmp (p, "yes") == 0 || strcmp (p, "true") == 0 - || strcmp (p, "on") == 0 || strcmp (p, "1") == 0) - ignore_unknown_config_keys = 1; - else - { - error (0, 0, "%s: unrecognized value '%s' for '%s'", - infopath, p, line); - goto error_return; - } - } - else if (ignore_unknown_config_keys) - ; - else - { - /* We may be dealing with a keyword which was added in a - subsequent version of CVS. In that case it is a good idea - to complain, as (1) the keyword might enable a behavior like - alternate locking behavior, in which it is dangerous and hard - to detect if some CVS's have it one way and others have it - the other way, (2) in general, having us not do what the user - had in mind when they put in the keyword violates the - principle of least surprise. Note that one corollary is - adding new keywords to your CVSROOT/config file is not - particularly recommended unless you are planning on using - the new features. */ - error (0, 0, "%s: unrecognized keyword '%s'", - infopath, line); - goto error_return; - } - } - if (ferror (fp_info)) - { - error (0, errno, "cannot read %s", infopath); - goto error_return; - } - if (fclose (fp_info) < 0) - { - error (0, errno, "cannot close %s", infopath); - goto error_return; - } -set_defaults_and_return: - if (!logHistory) - logHistory = xstrdup (ALL_HISTORY_REC_TYPES); - free (infopath); - if (line != NULL) - free (line); - return 0; - - error_return: - if (!logHistory) - logHistory = xstrdup (ALL_HISTORY_REC_TYPES); - if (infopath != NULL) - free (infopath); - if (line != NULL) - free (line); - return -1; -} diff --git a/contrib/cvs/src/patch.c b/contrib/cvs/src/patch.c deleted file mode 100644 index 65f5051..0000000 --- a/contrib/cvs/src/patch.c +++ /dev/null @@ -1,849 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Patch - * - * Create a Larry Wall format "patch" file between a previous release and the - * current head of a module, or between two releases. Can specify the - * release as either a date or a revision number. - * - * $FreeBSD$ - */ - -#include <assert.h> -#include "cvs.h" -#include "getline.h" - -static RETSIGTYPE patch_cleanup PROTO((void)); -static Dtype patch_dirproc PROTO ((void *callerdat, const char *dir, - const char *repos, const char *update_dir, - List *entries)); -static int patch_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static int patch_proc PROTO((int argc, char **argv, char *xwhere, - char *mwhere, char *mfile, int shorten, - int local_specified, char *mname, char *msg)); - -static int force_tag_match = 1; -static int patch_short = 0; -static int toptwo_diffs = 0; -static char *options = NULL; -static char *rev1 = NULL; -static int rev1_validated = 0; -static char *rev2 = NULL; -static int rev2_validated = 0; -static char *date1 = NULL; -static char *date2 = NULL; -static char *tmpfile1 = NULL; -static char *tmpfile2 = NULL; -static char *tmpfile3 = NULL; -static int unidiff = 0; - -static const char *const patch_usage[] = -{ - "Usage: %s %s [-flR] [-c|-u] [-s|-t] [-V %%d] [-k kopt]\n", - " -r rev|-D date [-r rev2 | -D date2] modules...\n", - "\t-f\tForce a head revision match if tag/date not found.\n", - "\t-l\tLocal directory only, not recursive\n", - "\t-R\tProcess directories recursively.\n", - "\t-c\tContext diffs (default)\n", - "\t-u\tUnidiff format.\n", - "\t-s\tShort patch - one liner per file.\n", - "\t-t\tTop two diffs - last change made to the file.\n", - "\t-V vers\tUse RCS Version \"vers\" for keyword expansion.\n", - "\t-k kopt\tSpecify keyword expansion mode.\n", - "\t-D date\tDate.\n", - "\t-r rev\tRevision - symbolic or numeric.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - - - -int -patch (argc, argv) - int argc; - char **argv; -{ - register int i; - int local = 0; - int c; - int err = 0; - DBM *db; - - if (argc == -1) - usage (patch_usage); - - optind = 0; - while ((c = getopt (argc, argv, "+V:k:cuftsQqlRD:r:")) != -1) - { - switch (c) - { - case 'Q': - case 'q': - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) - error (1, 0, - "-q or -Q must be specified before \"%s\"", - cvs_cmd_name); - break; - case 'f': - force_tag_match = 0; - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 't': - toptwo_diffs = 1; - break; - case 's': - patch_short = 1; - break; - case 'D': - if (rev2 != NULL || date2 != NULL) - error (1, 0, - "no more than two revisions/dates can be specified"); - if (rev1 != NULL || date1 != NULL) - date2 = Make_Date (optarg); - else - date1 = Make_Date (optarg); - break; - case 'r': - if (rev2 != NULL || date2 != NULL) - error (1, 0, - "no more than two revisions/dates can be specified"); - if (rev1 != NULL || date1 != NULL) - rev2 = optarg; - else - rev1 = optarg; - break; - case 'k': - if (options) - free (options); - options = RCS_check_kflag (optarg); - break; - case 'V': - /* This option is pretty seriously broken: - 1. It is not clear what it does (does it change keyword - expansion behavior? If so, how? Or does it have - something to do with what version of RCS we are using? - Or the format we write RCS files in?). - 2. Because both it and -k use the options variable, - specifying both -V and -k doesn't work. - 3. At least as of CVS 1.9, it doesn't work (failed - assertion in RCS_checkout where it asserts that options - starts with -k). Few people seem to be complaining. - In the future (perhaps the near future), I have in mind - removing it entirely, and updating NEWS and cvs.texinfo, - but in case it is a good idea to give people more time - to complain if they would miss it, I'll just add this - quick and dirty error message for now. */ - error (1, 0, - "the -V option is obsolete and should not be used"); -#if 0 - if (atoi (optarg) <= 0) - error (1, 0, "must specify a version number to -V"); - if (options) - free (options); - options = xmalloc (strlen (optarg) + 1 + 2); /* for the -V */ - (void) sprintf (options, "-V%s", optarg); -#endif - break; - case 'u': - unidiff = 1; /* Unidiff */ - break; - case 'c': /* Context diff */ - unidiff = 0; - break; - case '?': - default: - usage (patch_usage); - break; - } - } - argc -= optind; - argv += optind; - - /* Sanity checks */ - if (argc < 1) - usage (patch_usage); - - if (toptwo_diffs && patch_short) - error (1, 0, "-t and -s options are mutually exclusive"); - if (toptwo_diffs && (date1 != NULL || date2 != NULL || - rev1 != NULL || rev2 != NULL)) - error (1, 0, "must not specify revisions/dates with -t option!"); - - if (!toptwo_diffs && (date1 == NULL && date2 == NULL && - rev1 == NULL && rev2 == NULL)) - error (1, 0, "must specify at least one revision/date!"); - if (date1 != NULL && date2 != NULL) - if (RCS_datecmp (date1, date2) >= 0) - error (1, 0, "second date must come after first date!"); - - /* if options is NULL, make it a NULL string */ - if (options == NULL) - options = xstrdup (""); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - send_arg("-l"); - if (!force_tag_match) - send_arg("-f"); - if (toptwo_diffs) - send_arg("-t"); - if (patch_short) - send_arg("-s"); - if (unidiff) - send_arg("-u"); - - if (rev1) - option_with_arg ("-r", rev1); - if (date1) - client_senddate (date1); - if (rev2) - option_with_arg ("-r", rev2); - if (date2) - client_senddate (date2); - if (options[0] != '\0') - send_arg (options); - - { - int i; - for (i = 0; i < argc; ++i) - send_arg (argv[i]); - } - - send_to_server ("rdiff\012", 0); - return get_responses_and_close (); - } -#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 -#ifdef SIGINT - (void)SIG_register (SIGINT, patch_cleanup); -#endif -#ifdef SIGQUIT - (void)SIG_register (SIGQUIT, patch_cleanup); -#endif -#ifdef SIGPIPE - (void)SIG_register (SIGPIPE, patch_cleanup); -#endif -#ifdef SIGTERM - (void)SIG_register (SIGTERM, patch_cleanup); -#endif - - db = open_module (); - for (i = 0; i < argc; i++) - err += do_module (db, argv[i], PATCH, "Patching", patch_proc, - (char *)NULL, 0, local, 0, 0, (char *)NULL); - close_module (db); - free (options); - patch_cleanup (); - return err; -} - - - -/* - * callback proc for doing the real work of patching - */ -/* ARGSUSED */ -static int -patch_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified, - mname, msg) - int argc; - char **argv; - char *xwhere; - char *mwhere; - char *mfile; - int shorten; - int local_specified; - char *mname; - char *msg; -{ - char *myargv[2]; - int err = 0; - int which; - char *repository; - char *where; - - repository = xmalloc (strlen (current_parsed_root->directory) - + strlen (argv[0]) - + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2); - (void)sprintf (repository, "%s/%s", - current_parsed_root->directory, argv[0]); - where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1) - + 1); - (void)strcpy (where, argv[0]); - - /* if mfile isn't null, we need to set up to do only part of the module */ - if (mfile != NULL) - { - char *cp; - char *path; - - /* if the portion of the module is a path, put the dir part on repos */ - if ((cp = strrchr (mfile, '/')) != NULL) - { - *cp = '\0'; - (void)strcat (repository, "/"); - (void)strcat (repository, mfile); - (void)strcat (where, "/"); - (void)strcat (where, mfile); - mfile = cp + 1; - } - - /* take care of the rest */ - path = xmalloc (strlen (repository) + strlen (mfile) + 2); - (void)sprintf (path, "%s/%s", repository, mfile); - if (isdir (path)) - { - /* directory means repository gets the dir tacked on */ - (void)strcpy (repository, path); - (void)strcat (where, "/"); - (void)strcat (where, mfile); - } - else - { - myargv[0] = argv[0]; - myargv[1] = mfile; - argc = 2; - argv = myargv; - } - free (path); - } - - /* cd to the starting repository */ - if ( CVS_CHDIR (repository) < 0) - { - error (0, errno, "cannot chdir to %s", repository); - free (repository); - free (where); - return 1; - } - - if (force_tag_match) - which = W_REPOS | W_ATTIC; - else - which = W_REPOS; - - if (rev1 != NULL && !rev1_validated) - { - tag_check_valid (rev1, argc - 1, argv + 1, local_specified, 0, - repository); - rev1_validated = 1; - } - if (rev2 != NULL && !rev2_validated) - { - tag_check_valid (rev2, argc - 1, argv + 1, local_specified, 0, - repository); - rev2_validated = 1; - } - - /* start the recursion processor */ - err = start_recursion (patch_fileproc, (FILESDONEPROC)NULL, patch_dirproc, - (DIRLEAVEPROC)NULL, NULL, - argc - 1, argv + 1, local_specified, - which, 0, CVS_LOCK_READ, where, 1, repository); - free (repository); - free (where); - - return err; -} - - - -/* - * Called to examine a particular RCS file, as appropriate with the options - * that were set above. - */ -/* ARGSUSED */ -static int -patch_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - struct utimbuf t; - char *vers_tag, *vers_head; - char *rcs = NULL; - char *rcs_orig = NULL; - RCSNode *rcsfile; - FILE *fp1, *fp2, *fp3; - int ret = 0; - int isattic = 0; - int retcode = 0; - char *file1; - char *file2; - char *strippath; - char *line1, *line2; - size_t line1_chars_allocated; - size_t line2_chars_allocated; - char *cp1, *cp2; - FILE *fp; - int line_length; - int dargc = 0; - size_t darg_allocated = 0; - char **dargv = NULL; - - line1 = NULL; - line1_chars_allocated = 0; - line2 = NULL; - line2_chars_allocated = 0; - vers_tag = vers_head = NULL; - - /* find the parsed rcs file */ - if ((rcsfile = finfo->rcs) == NULL) - { - ret = 1; - goto out2; - } - if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC)) - isattic = 1; - - rcs_orig = rcs = xmalloc (strlen (finfo->file) + sizeof (RCSEXT) + 5); - (void) sprintf (rcs, "%s%s", finfo->file, RCSEXT); - - /* if vers_head is NULL, may have been removed from the release */ - if (isattic && rev2 == NULL && date2 == NULL) - vers_head = NULL; - else - { - vers_head = RCS_getversion (rcsfile, rev2, date2, force_tag_match, - (int *) NULL); - if (vers_head != NULL && RCS_isdead (rcsfile, vers_head)) - { - free (vers_head); - vers_head = NULL; - } - } - - if (toptwo_diffs) - { - if (vers_head == NULL) - { - ret = 1; - goto out2; - } - - if (!date1) - date1 = xmalloc (MAXDATELEN); - *date1 = '\0'; - if (RCS_getrevtime (rcsfile, vers_head, date1, 1) == (time_t)-1) - { - if (!really_quiet) - error (0, 0, "cannot find date in rcs file %s revision %s", - rcs, vers_head); - ret = 1; - goto out2; - } - } - vers_tag = RCS_getversion (rcsfile, rev1, date1, force_tag_match, - (int *) NULL); - if (vers_tag != NULL && RCS_isdead (rcsfile, vers_tag)) - { - free (vers_tag); - vers_tag = NULL; - } - - if ((vers_tag == NULL && vers_head == NULL) || - (vers_tag != NULL && vers_head != NULL && - strcmp (vers_head, vers_tag) == 0)) - { - /* Nothing known about specified revs or - * not changed between releases. - */ - ret = 0; - goto out2; - } - - if( patch_short && ( vers_tag == NULL || vers_head == NULL ) ) - { - /* For adds & removes with a short patch requested, we can print our - * error message now and get out. - */ - cvs_output ("File ", 0); - cvs_output (finfo->fullname, 0); - if (vers_tag == NULL) - { - cvs_output( " is new; ", 0 ); - cvs_output( rev2 ? rev2 : date2 ? date2 : "current", 0 ); - cvs_output( " revision ", 0 ); - cvs_output (vers_head, 0); - cvs_output ("\n", 1); - } - else - { - cvs_output( " is removed; ", 0 ); - cvs_output( rev1 ? rev1 : date1, 0 ); - cvs_output( " revision ", 0 ); - cvs_output( vers_tag, 0 ); - cvs_output ("\n", 1); - } - ret = 0; - goto out2; - } - - /* Create 3 empty files. I'm not really sure there is any advantage - * to doing so now rather than just waiting until later. - * - * There is - cvs_temp_file opens the file so that it can guarantee that - * we have exclusive write access to the file. Unfortunately we spoil that - * by closing it and reopening it again. Of course any better solution - * requires that the RCS functions accept open file pointers rather than - * simple file names. - */ - if ((fp1 = cvs_temp_file (&tmpfile1)) == NULL) - { - error (0, errno, "cannot create temporary file %s", - tmpfile1 ? tmpfile1 : "(null)"); - ret = 1; - goto out; - } - else - if (fclose (fp1) < 0) - error (0, errno, "warning: cannot close %s", tmpfile1); - if ((fp2 = cvs_temp_file (&tmpfile2)) == NULL) - { - error (0, errno, "cannot create temporary file %s", - tmpfile2 ? tmpfile2 : "(null)"); - ret = 1; - goto out; - } - else - if (fclose (fp2) < 0) - error (0, errno, "warning: cannot close %s", tmpfile2); - if ((fp3 = cvs_temp_file (&tmpfile3)) == NULL) - { - error (0, errno, "cannot create temporary file %s", - tmpfile3 ? tmpfile3 : "(null)"); - ret = 1; - goto out; - } - else - if (fclose (fp3) < 0) - error (0, errno, "warning: cannot close %s", tmpfile3); - - if (vers_tag != NULL) - { - retcode = RCS_checkout (rcsfile, (char *)NULL, vers_tag, - rev1, options, tmpfile1, - (RCSCHECKOUTPROC)NULL, (void *)NULL); - if (retcode != 0) - { - error (0, 0, - "cannot check out revision %s of %s", vers_tag, rcs); - ret = 1; - goto out; - } - memset ((char *) &t, 0, sizeof (t)); - if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_tag, - (char *) 0, 0)) != -1) - /* I believe this timestamp only affects the dates in our diffs, - and therefore should be on the server, not the client. */ - (void) utime (tmpfile1, &t); - } - else if (toptwo_diffs) - { - ret = 1; - goto out; - } - if (vers_head != NULL) - { - retcode = RCS_checkout (rcsfile, (char *)NULL, vers_head, - rev2, options, tmpfile2, - (RCSCHECKOUTPROC)NULL, (void *)NULL); - if (retcode != 0) - { - error (0, 0, - "cannot check out revision %s of %s", vers_head, rcs); - ret = 1; - goto out; - } - if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_head, - (char *)0, 0)) != -1) - /* I believe this timestamp only affects the dates in our diffs, - and therefore should be on the server, not the client. */ - (void)utime (tmpfile2, &t); - } - - if (unidiff) run_add_arg_p (&dargc, &darg_allocated, &dargv, "-u"); - else run_add_arg_p (&dargc, &darg_allocated, &dargv, "-c"); - switch (diff_exec (tmpfile1, tmpfile2, NULL, NULL, dargc, dargv, - tmpfile3)) - { - case -1: /* fork/wait failure */ - error (1, errno, "fork for diff failed on %s", rcs); - break; - case 0: /* nothing to do */ - break; - case 1: - /* - * The two revisions are really different, so read the first two - * lines of the diff output file, and munge them to include more - * reasonable file names that "patch" will understand, unless the - * user wanted a short patch. In that case, just output the short - * message. - */ - if( patch_short ) - { - cvs_output ("File ", 0); - cvs_output (finfo->fullname, 0); - cvs_output (" changed from revision ", 0); - cvs_output (vers_tag, 0); - cvs_output (" to ", 0); - cvs_output (vers_head, 0); - cvs_output ("\n", 1); - ret = 0; - goto out; - } - - /* Output an "Index:" line for patch to use */ - cvs_output ("Index: ", 0); - cvs_output (finfo->fullname, 0); - cvs_output ("\n", 1); - - /* Now the munging. */ - fp = open_file (tmpfile3, "r"); - if (getline (&line1, &line1_chars_allocated, fp) < 0 || - getline (&line2, &line2_chars_allocated, fp) < 0) - { - if (feof (fp)) - error (0, 0, "\ -failed to read diff file header %s for %s: end of file", tmpfile3, rcs); - else - error (0, errno, - "failed to read diff file header %s for %s", - tmpfile3, rcs); - ret = 1; - if (fclose (fp) < 0) - error (0, errno, "error closing %s", tmpfile3); - goto out; - } - if (!unidiff) - { - if (strncmp (line1, "*** ", 4) != 0 || - strncmp (line2, "--- ", 4) != 0 || - (cp1 = strchr (line1, '\t')) == NULL || - (cp2 = strchr (line2, '\t')) == NULL) - { - error (0, 0, "invalid diff header for %s", rcs); - ret = 1; - if (fclose (fp) < 0) - error (0, errno, "error closing %s", tmpfile3); - goto out; - } - } - else - { - if (strncmp (line1, "--- ", 4) != 0 || - strncmp (line2, "+++ ", 4) != 0 || - (cp1 = strchr (line1, '\t')) == NULL || - (cp2 = strchr (line2, '\t')) == NULL) - { - error (0, 0, "invalid unidiff header for %s", rcs); - ret = 1; - if (fclose (fp) < 0) - error (0, errno, "error closing %s", tmpfile3); - goto out; - } - } - assert (current_parsed_root != NULL); - assert (current_parsed_root->directory != NULL); - { - strippath = xmalloc (strlen (current_parsed_root->directory) - + 2); - (void)sprintf (strippath, "%s/", - current_parsed_root->directory); - } - /*else - strippath = xstrdup (REPOS_STRIP); */ - if (strncmp (rcs, strippath, strlen (strippath)) == 0) - rcs += strlen (strippath); - free (strippath); - if (vers_tag != NULL) - { - file1 = xmalloc (strlen (finfo->fullname) - + strlen (vers_tag) - + 10); - (void)sprintf (file1, "%s:%s", finfo->fullname, vers_tag); - } - else - { - file1 = xstrdup (DEVNULL); - } - file2 = xmalloc (strlen (finfo->fullname) - + (vers_head != NULL ? strlen (vers_head) : 10) - + 10); - (void)sprintf (file2, "%s:%s", finfo->fullname, - vers_head ? vers_head : "removed"); - - /* Note that the string "diff" is specified by POSIX (for -c) - and is part of the diff output format, not the name of a - program. */ - if (unidiff) - { - cvs_output ("diff -u ", 0); - cvs_output (file1, 0); - cvs_output (" ", 1); - cvs_output (file2, 0); - cvs_output ("\n", 1); - - cvs_output ("--- ", 0); - cvs_output (file1, 0); - cvs_output (cp1, 0); - cvs_output ("+++ ", 0); - } - else - { - cvs_output ("diff -c ", 0); - cvs_output (file1, 0); - cvs_output (" ", 1); - cvs_output (file2, 0); - cvs_output ("\n", 1); - - cvs_output ("*** ", 0); - cvs_output (file1, 0); - cvs_output (cp1, 0); - cvs_output ("--- ", 0); - } - - cvs_output (finfo->fullname, 0); - cvs_output (cp2, 0); - - /* spew the rest of the diff out */ - while ((line_length - = getline (&line1, &line1_chars_allocated, fp)) - >= 0) - cvs_output (line1, 0); - if (line_length < 0 && !feof (fp)) - error (0, errno, "cannot read %s", tmpfile3); - - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", tmpfile3); - free (file1); - free (file2); - break; - default: - error (0, 0, "diff failed for %s", finfo->fullname); - } - out: - if (line1) - free (line1); - if (line2) - free (line2); - if (tmpfile1 != NULL) - { - if (CVS_UNLINK (tmpfile1) < 0) - error (0, errno, "cannot unlink %s", tmpfile1); - free (tmpfile1); - tmpfile1 = NULL; - } - if (tmpfile2 != NULL) - { - if (CVS_UNLINK (tmpfile2) < 0) - error (0, errno, "cannot unlink %s", tmpfile2); - free (tmpfile2); - tmpfile2 = NULL; - } - if (tmpfile3 != NULL) - { - if (CVS_UNLINK (tmpfile3) < 0) - error (0, errno, "cannot unlink %s", tmpfile3); - free (tmpfile3); - tmpfile3 = NULL; - } - - if (dargc) - { - run_arg_free_p (dargc, dargv); - free (dargv); - } - - out2: - if (vers_tag != NULL) - free (vers_tag); - if (vers_head != NULL) - free (vers_head); - if (rcs_orig) - free (rcs_orig); - return ret; -} - - - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -patch_dirproc (callerdat, dir, repos, update_dir, entries) - void *callerdat; - const char *dir; - const char *repos; - const char *update_dir; - List *entries; -{ - if (!quiet) - error (0, 0, "Diffing %s", update_dir); - return (R_PROCESS); -} - -/* - * Clean up temporary files - */ -static RETSIGTYPE -patch_cleanup () -{ - /* Note that the checks for existence_error are because we are - called from a signal handler, without SIG_begincrsect, so - we don't know whether the files got created. */ - - if (tmpfile1 != NULL) - { - if (unlink_file (tmpfile1) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", tmpfile1); - free (tmpfile1); - } - if (tmpfile2 != NULL) - { - if (unlink_file (tmpfile2) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", tmpfile2); - free (tmpfile2); - } - if (tmpfile3 != NULL) - { - if (unlink_file (tmpfile3) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", tmpfile3); - free (tmpfile3); - } - tmpfile1 = tmpfile2 = tmpfile3 = NULL; -} diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c deleted file mode 100644 index 3358e91..0000000 --- a/contrib/cvs/src/rcs.c +++ /dev/null @@ -1,9074 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * The routines contained in this file do all the rcs file parsing and - * manipulation - * - * $FreeBSD$ - */ - -#include <assert.h> -#include "cvs.h" -#include "edit.h" -#include "hardlink.h" - -/* These need to be source after cvs.h or HAVE_MMAP won't be set... */ -#ifdef HAVE_MMAP -# include <sys/mman.h> -# ifndef HAVE_GETPAGESIZE -# include "getpagesize.h" -# endif -# ifndef MAP_FAILED -# define MAP_FAILED NULL -# endif -#endif - -#ifdef MMAP_FALLBACK_TEST -void *my_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) -{ - if (rand() & 1) return mmap(addr, len, prot, flags, fd, offset); - return NULL; -} -#define mmap my_mmap -#endif - -int datesep = '/'; -int preserve_perms = 0; - -/* The RCS -k options, and a set of enums that must match the array. - These come first so that we can use enum kflag in function - prototypes. */ -static const char *const kflags[] = - {"kv", "kvl", "k", "v", "o", "b", (char *) NULL}; -enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B }; - -/* A structure we use to buffer the contents of an RCS file. The - various fields are only referenced directly by the rcsbuf_* - functions. We declare the struct here so that we can allocate it - on the stack, rather than in memory. */ - -struct rcsbuffer -{ - /* Points to the current position in the buffer. */ - char *ptr; - /* Points just after the last valid character in the buffer. */ - char *ptrend; - /* The file. */ - FILE *fp; - /* The name of the file, used for error messages. */ - const char *filename; - /* The starting file position of the data in the buffer. */ - unsigned long pos; - /* The length of the value. */ - size_t vlen; - /* Whether the value contains an '@' string. If so, we can not - compress whitespace characters. */ - int at_string; - /* The number of embedded '@' characters in an '@' string. If - this is non-zero, we must search the string for pairs of '@' - and convert them to a single '@'. */ - int embedded_at; - /* Whether the buffer has been mmap'ed or not. */ - int mmapped; -}; - -static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile)); -static char *RCS_getdatebranch PROTO((RCSNode * rcs, const char *date, - const char *branch)); -static void rcsbuf_open PROTO ((struct rcsbuffer *, FILE *fp, - const char *filename, unsigned long pos)); -static void rcsbuf_close PROTO ((struct rcsbuffer *)); -static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp, - char **valp)); -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, - size_t *lenp)); -static void rcsbuf_valpolish_internal PROTO ((struct rcsbuffer *, char *to, - const char *from, size_t *lenp)); -static unsigned long rcsbuf_ftell PROTO ((struct rcsbuffer *)); -static void rcsbuf_get_buffered PROTO ((struct rcsbuffer *, char **datap, - size_t *lenp)); -static void rcsbuf_cache PROTO ((RCSNode *, struct rcsbuffer *)); -static void rcsbuf_cache_close PROTO ((void)); -static void rcsbuf_cache_open PROTO ((RCSNode *, long, FILE **, - struct rcsbuffer *)); -static int checkmagic_proc PROTO((Node *p, void *closure)); -static void do_branches PROTO((List * list, char *val)); -static void do_symbols PROTO((List * list, char *val)); -static void do_locks PROTO((List * list, char *val)); -static void free_rcsnode_contents PROTO((RCSNode *)); -static void free_rcsvers_contents PROTO((RCSVers *)); -static void rcsvers_delproc PROTO((Node * p)); -static char *translate_symtag PROTO((RCSNode *, const char *)); -static char *RCS_addbranch PROTO ((RCSNode *, const char *)); -static char *truncate_revnum_in_place PROTO ((char *)); -static char *truncate_revnum PROTO ((const char *)); -static char *printable_date PROTO((const char *)); -static char *escape_keyword_value PROTO ((const char *, int *)); -static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *, - const char *, size_t, enum kflag, char *, - size_t, char **, size_t *)); -static void cmp_file_buffer PROTO((void *, const char *, size_t)); - -/* Routines for reading, parsing and writing RCS files. */ -static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **, - char **)); -static Deltatext *RCS_getdeltatext PROTO ((RCSNode *, FILE *, - struct rcsbuffer *)); -static void freedeltatext PROTO ((Deltatext *)); - -static void RCS_putadmin PROTO ((RCSNode *, FILE *)); -static void RCS_putdtree PROTO ((RCSNode *, char *, FILE *)); -static void RCS_putdesc PROTO ((RCSNode *, FILE *)); -static void putdelta PROTO ((RCSVers *, FILE *)); -static int putrcsfield_proc PROTO ((Node *, void *)); -static int putsymbol_proc PROTO ((Node *, void *)); -static void RCS_copydeltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, - FILE *, Deltatext *, char *)); -static int count_delta_actions PROTO ((Node *, void *)); -static void putdeltatext PROTO ((FILE *, Deltatext *)); - -static FILE *rcs_internal_lockfile PROTO ((char *)); -static void rcs_internal_unlockfile PROTO ((FILE *, char *)); -static char *rcs_lockfilename PROTO ((const char *)); - -/* The RCS file reading functions are called a lot, and they do some - string comparisons. This macro speeds things up a bit by skipping - the function call when the first characters are different. It - evaluates its arguments multiple times. */ -#define STREQ(a, b) (*(char *)(a) == *(char *)(b) && strcmp ((a), (b)) == 0) - -static char * getfullCVSname PROTO ((char *, char **)); - -/* - * We don't want to use isspace() from the C library because: - * - * 1. The definition of "whitespace" in RCS files includes ASCII - * backspace, but the C locale doesn't. - * 2. isspace is an very expensive function call in some implementations - * due to the addition of wide character support. - */ -static const char spacetab[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */ -}; - -#define whitespace(c) (spacetab[(unsigned char)c] != 0) - -static char *rcs_lockfile; -static int rcs_lockfd = -1; - - - -/* - * char * - * locate_rcs ( const char* file, const char *repository , int *inattic ) - * - * Find an RCS file in the repository, case insensitively when the cased name - * doesn't exist, we are running as the server, and a client has asked us to - * ignore case. - * - * Most parts of CVS will want to rely instead on RCS_parse which calls this - * function and is called by recurse.c which then puts the result in useful - * places like the rcs field of struct file_info. - * - * INPUTS - * - * repository the repository (including the directory) - * file the filename within that directory (without RCSEXT). - * inattic NULL or a pointer to the output boolean - * - * OUTPUTS - * - * inattic If this input was non-null, the destination will be - * set to true if the file was found in the attic or - * false if not. If no RCS file is found, this value - * is undefined. - * - * RETURNS - * - * a newly-malloc'd array containing the absolute pathname of the RCS - * file that was found or NULL when none was found. - * - * ERRORS - * - * errno can be set by the return value of the final call to - * locate_file_in_dir(). This should resolve to the system's existence error - * value (sometime ENOENT) if the Attic directory did not exist and ENOENT if - * the Attic was found but no matching files were found in the Attic or its - * parent. - */ -static char * -locate_rcs (repository, file, inattic) - const char *repository; - const char *file; - int *inattic; -{ - char *retval; - - /* First, try to find the file as cased. */ - retval = xmalloc (strlen (repository) - + sizeof (CVSATTIC) - + strlen (file) - + sizeof (RCSEXT) - + 3); - sprintf (retval, "%s/%s%s", repository, file, RCSEXT); - if (isreadable (retval)) - { - if (inattic) - *inattic = 0; - return retval; - } - sprintf (retval, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT); - if (isreadable (retval)) - { - if (inattic) - *inattic = 1; - return retval; - } - free (retval); - - return NULL; -} - - - -/* A few generic thoughts on error handling, in particular the - printing of unexpected characters that we find in the RCS file - (that is, why we use '\x%x' rather than %c or some such). - - * Avoiding %c means we don't have to worry about what is printable - and other such stuff. In error handling, often better to keep it - simple. - - * Hex rather than decimal or octal because character set standards - tend to use hex. - - * Saying "character 0x%x" might make it sound like we are printing - a file offset. So we use '\x%x'. - - * Would be nice to print the offset within the file, but I can - imagine various portability hassles (in particular, whether - unsigned long is always big enough to hold file offsets). */ - -/* Parse an rcsfile given a user file name and a repository. If there is - an error, we print an error message and return NULL. If the file - does not exist, we return NULL without printing anything (I'm not - sure this allows the caller to do anything reasonable, but it is - the current behavior). */ -RCSNode * -RCS_parse (file, repos) - const char *file; - const char *repos; -{ - RCSNode *rcs; - FILE *fp; - RCSNode *retval = NULL; - char *rcsfile; - int inattic; - - /* We're creating a new RCSNode, so there is no hope of finding it - in the cache. */ - rcsbuf_cache_close (); - - if ((rcsfile = locate_rcs (repos, file, &inattic)) == NULL) - { - /* Handle the error cases */ - } - else if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) != NULL) - { - rcs = RCS_parsercsfile_i(fp, rcsfile); - if (rcs != NULL) - { - rcs->flags |= VALID; - if ( inattic ) - rcs->flags |= INATTIC; - } - - free ( rcsfile ); - retval = rcs; - } - else if (! existence_error (errno)) - { - error (0, errno, "cannot open %s", rcsfile); - free (rcsfile); - } - - return retval; -} - -/* - * Parse a specific rcsfile. - */ -RCSNode * -RCS_parsercsfile (rcsfile) - const char *rcsfile; -{ - FILE *fp; - RCSNode *rcs; - - /* We're creating a new RCSNode, so there is no hope of finding it - in the cache. */ - rcsbuf_cache_close (); - - /* open the rcsfile */ - if ((fp = CVS_FOPEN (rcsfile, FOPEN_BINARY_READ)) == NULL) - { - error (0, errno, "Couldn't open rcs file `%s'", rcsfile); - return (NULL); - } - - rcs = RCS_parsercsfile_i (fp, rcsfile); - - return (rcs); -} - - - -/* - */ -static RCSNode * -RCS_parsercsfile_i (fp, rcsfile) - FILE *fp; - const char *rcsfile; -{ - RCSNode *rdata; - struct rcsbuffer rcsbuf; - char *key, *value; - - /* make a node */ - rdata = (RCSNode *) xmalloc (sizeof (RCSNode)); - memset ((char *)rdata, 0, sizeof (RCSNode)); - rdata->refcount = 1; - rdata->path = xstrdup (rcsfile); - - /* Process HEAD, BRANCH, and EXPAND keywords from the RCS header. - - Most cvs operations on the main branch don't need any more - information. Those that do call RCS_reparsercsfile to parse - the rest of the header and the deltas. */ - - rcsbuf_open (&rcsbuf, fp, rcsfile, 0); - - if (! rcsbuf_getkey (&rcsbuf, &key, &value)) - goto l_error; - if (STREQ (key, RCSDESC)) - goto l_error; - - if (STREQ (RCSHEAD, key) && value != NULL) - rdata->head = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL); - - if (! rcsbuf_getkey (&rcsbuf, &key, &value)) - goto l_error; - if (STREQ (key, RCSDESC)) - goto l_error; - - if (STREQ (RCSBRANCH, key) && value != NULL) - { - char *cp; - - rdata->branch = rcsbuf_valcopy (&rcsbuf, value, 0, (size_t *)NULL); - if ((numdots (rdata->branch) & 1) != 0) - { - /* turn it into a branch if it's a revision */ - cp = strrchr (rdata->branch, '.'); - *cp = '\0'; - } - } - - /* Look ahead for expand, stopping when we see desc or a revision - number. */ - while (1) - { - char *cp; - - if (STREQ (RCSEXPAND, key)) - { - rdata->expand = rcsbuf_valcopy (&rcsbuf, value, 0, - (size_t *)NULL); - break; - } - - for (cp = key; - (isdigit ((unsigned char)*cp) || *cp == '.') && *cp != '\0'; - cp++) - /* do nothing */ ; - if (*cp == '\0') - break; - - if (STREQ (RCSDESC, key)) - break; - - if (! rcsbuf_getkey (&rcsbuf, &key, &value)) - break; - } - - rdata->flags |= PARTIAL; - - rcsbuf_cache (rdata, &rcsbuf); - - return rdata; - -l_error: - error (0, 0, "`%s' does not appear to be a valid rcs file", - rcsfile); - rcsbuf_close (&rcsbuf); - freercsnode (&rdata); - fclose (fp); - return NULL; -} - - - -/* Do the real work of parsing an RCS file. - - On error, die with a fatal error; if it returns at all it was successful. - - If PFP is NULL, close the file when done. Otherwise, leave it open - and store the FILE * in *PFP. */ -void -RCS_reparsercsfile (rdata, pfp, rcsbufp) - RCSNode *rdata; - FILE **pfp; - struct rcsbuffer *rcsbufp; -{ - FILE *fp; - char *rcsfile; - struct rcsbuffer rcsbuf; - Node *q, *kv; - RCSVers *vnode; - int gotkey; - char *cp; - char *key, *value; - - assert (rdata != NULL); - rcsfile = rdata->path; - - rcsbuf_cache_open (rdata, 0, &fp, &rcsbuf); - - /* make a node */ - /* This probably shouldn't be done until later: if a file has an - empty revision tree (which is permissible), rdata->versions - should be NULL. -twp */ - rdata->versions = getlist (); - - /* - * process all the special header information, break out when we get to - * the first revision delta - */ - gotkey = 0; - for (;;) - { - /* get the next key/value pair */ - if (!gotkey) - { - if (! rcsbuf_getkey (&rcsbuf, &key, &value)) - { - error (1, 0, "`%s' does not appear to be a valid rcs file", - rcsfile); - } - } - - gotkey = 0; - - /* Skip head, branch and expand tags; we already have them. */ - if (STREQ (key, RCSHEAD) - || STREQ (key, RCSBRANCH) - || STREQ (key, RCSEXPAND)) - { - continue; - } - - if (STREQ (key, "access")) - { - if (value != NULL) - { - /* We pass the POLISH parameter as 1 because - RCS_addaccess expects nothing but spaces. FIXME: - It would be easy and more efficient to change - RCS_addaccess. */ - if (rdata->access) - { - error (0, 0, - "Duplicate `access' keyword found in RCS file."); - free (rdata->access); - } - rdata->access = rcsbuf_valcopy (&rcsbuf, value, 1, NULL); - } - continue; - } - - /* We always save lock information, so that we can handle - -kkvl correctly when checking out a file. */ - if (STREQ (key, "locks")) - { - if (value != NULL) - { - if (rdata->locks_data) - { - error (0, 0, - "Duplicate `locks' keyword found in RCS file."); - free (rdata->locks_data); - } - rdata->locks_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); - } - if (! rcsbuf_getkey (&rcsbuf, &key, &value)) - { - error (1, 0, "premature end of file reading %s", rcsfile); - } - if (STREQ (key, "strict") && value == NULL) - { - rdata->strict_locks = 1; - } - else - gotkey = 1; - continue; - } - - if (STREQ (RCSSYMBOLS, key)) - { - if (value != NULL) - { - if (rdata->symbols_data) - { - error (0, 0, - "Duplicate `%s' keyword found in RCS file.", - RCSSYMBOLS); - free (rdata->symbols_data); - } - rdata->symbols_data = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); - } - continue; - } - - /* - * check key for '.''s and digits (probably a rev) if it is a - * revision or `desc', we are done with the headers and are down to the - * revision deltas, so we break out of the loop - */ - for (cp = key; - (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0'; - cp++) - /* do nothing */ ; - /* Note that when comparing with RCSDATE, we are not massaging - VALUE from the string found in the RCS file. This is OK - since we know exactly what to expect. */ - if (*cp == '\0' && strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) == 0) - break; - - if (STREQ (key, RCSDESC)) - break; - - if (STREQ (key, "comment")) - { - if (rdata->comment) - { - error (0, 0, - "warning: duplicate key `%s' in RCS file `%s'", - key, rcsfile); - free (rdata->comment); - } - rdata->comment = rcsbuf_valcopy (&rcsbuf, value, 0, NULL); - continue; - } - if (rdata->other == NULL) - rdata->other = getlist (); - kv = getnode (); - 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 (rdata->other, kv) != 0) - { - error (0, 0, "warning: duplicate key `%s' in RCS file `%s'", - key, rcsfile); - freenode (kv); - } - - /* if we haven't grabbed it yet, we didn't want it */ - } - - /* We got out of the loop, so we have the first part of the first - revision delta in KEY (the revision) and VALUE (the date key - and its value). This is what getdelta expects to receive. */ - - while ((vnode = getdelta (&rcsbuf, rcsfile, &key, &value)) != NULL) - { - /* get the node */ - q = getnode (); - q->type = RCSVERS; - q->delproc = rcsvers_delproc; - q->data = vnode; - q->key = vnode->version; - - /* add the nodes to the list */ - if (addnode (rdata->versions, q)) - error (1, 0, "Multiple %s revision deltas found in `%s'", - q->key, rcsfile); - } - - /* Here KEY and VALUE are whatever caused getdelta to return NULL. */ - - if (STREQ (key, RCSDESC)) - { - if (rdata->desc != NULL) - { - error (0, 0, - "warning: duplicate key `%s' in RCS file `%s'", - key, rcsfile); - free (rdata->desc); - } - rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL); - } - - rdata->delta_pos = rcsbuf_ftell (&rcsbuf); - - if (pfp == NULL) - rcsbuf_cache (rdata, &rcsbuf); - else - { - *pfp = fp; - *rcsbufp = rcsbuf; - } - rdata->flags &= ~PARTIAL; -} - -/* Move RCS into or out of the Attic, depending on TOATTIC. If the - file is already in the desired place, return without doing - anything. At some point may want to think about how this relates - to RCS_rewrite but that is a bit hairy (if one wants renames to be - atomic, or that kind of thing). If there is an error, print a message - and return 1. On success, return 0. */ -int -RCS_setattic (rcs, toattic) - RCSNode *rcs; - int toattic; -{ - char *newpath; - const char *p; - char *q; - - /* Some systems aren't going to let us rename an open file. */ - rcsbuf_cache_close (); - - /* Could make the pathname computations in this file, and probably - in other parts of rcs.c too, easier if the REPOS and FILE - arguments to RCS_parse got stashed in the RCSNode. */ - - if (toattic) - { - mode_t omask; - - if (rcs->flags & INATTIC) - return 0; - - /* Example: rcs->path is "/foo/bar/baz,v". */ - newpath = xmalloc (strlen (rcs->path) + sizeof CVSATTIC + 5); - p = last_component (rcs->path); - strncpy (newpath, rcs->path, p - rcs->path); - strcpy (newpath + (p - rcs->path), CVSATTIC); - - /* Create the Attic directory if it doesn't exist. */ - omask = umask (cvsumask); - if (CVS_MKDIR (newpath, 0777) < 0 && errno != EEXIST) - error (0, errno, "cannot make directory %s", newpath); - (void) umask (omask); - - strcat (newpath, "/"); - strcat (newpath, p); - - if (CVS_RENAME (rcs->path, newpath) < 0) - { - int save_errno = errno; - - /* The checks for isreadable look awfully fishy, but - I'm going to leave them here for now until I - can think harder about whether they take care of - some cases which should be handled somehow. */ - - if (isreadable (rcs->path) || !isreadable (newpath)) - { - error (0, save_errno, "cannot rename %s to %s", - rcs->path, newpath); - free (newpath); - return 1; - } - } - } - else - { - if (!(rcs->flags & INATTIC)) - return 0; - - newpath = xmalloc (strlen (rcs->path)); - - /* Example: rcs->path is "/foo/bar/Attic/baz,v". */ - p = last_component (rcs->path); - strncpy (newpath, rcs->path, p - rcs->path - 1); - newpath[p - rcs->path - 1] = '\0'; - q = newpath + (p - rcs->path - 1) - (sizeof CVSATTIC - 1); - assert (strncmp (q, CVSATTIC, sizeof CVSATTIC - 1) == 0); - strcpy (q, p); - - if (CVS_RENAME (rcs->path, newpath) < 0) - { - error (0, errno, "failed to move `%s' out of the attic", - rcs->path); - free (newpath); - return 1; - } - } - - free (rcs->path); - rcs->path = newpath; - - return 0; -} - -/* - * Fully parse the RCS file. Store all keyword/value pairs, fetch the - * log messages for each revision, and fetch add and delete counts for - * each revision (we could fetch the entire text for each revision, - * but the only caller, log_fileproc, doesn't need that information, - * so we don't waste the memory required to store it). The add and - * delete counts are stored on the OTHER field of the RCSVERSNODE - * structure, under the names ";add" and ";delete", so that we don't - * waste the memory space of extra fields in RCSVERSNODE for code - * which doesn't need this information. - */ - -void -RCS_fully_parse (rcs) - RCSNode *rcs; -{ - FILE *fp; - struct rcsbuffer rcsbuf; - - RCS_reparsercsfile (rcs, &fp, &rcsbuf); - - while (1) - { - char *key, *value; - Node *vers; - RCSVers *vnode; - - /* Rather than try to keep track of how much information we - have read, just read to the end of the file. */ - if (!rcsbuf_getrevnum (&rcsbuf, &key)) - break; - - vers = findnode (rcs->versions, key); - if (!vers) - error (1, 0, - "Delta text %s without revision information in `%s'.", - key, rcs->path); - - vnode = vers->data; - - while (rcsbuf_getkey (&rcsbuf, &key, &value)) - { - if (!STREQ (key, "text")) - { - Node *kv; - - if (vnode->other == NULL) - vnode->other = getlist (); - kv = getnode (); - 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, kv) != 0) - { - error (0, 0, - "\ -warning: duplicate key `%s' in version `%s' of RCS file `%s'", - key, vnode->version, rcs->path); - freenode (kv); - } - - continue; - } - - if (!STREQ (vnode->version, rcs->head)) - { - unsigned long add, del; - char buf[50]; - Node *kv; - - /* This is a change text. Store the add and delete - counts. */ - add = 0; - del = 0; - if (value != NULL) - { - size_t vallen; - const char *cp; - - rcsbuf_valpolish (&rcsbuf, value, 0, &vallen); - cp = value; - while (cp < value + vallen) - { - char op; - unsigned long count; - - op = *cp++; - if (op != 'a' && op != 'd') - error (1, 0, "\ -unrecognized operation '\\x%x' in %s revision %s", - op, rcs->path, vnode->version); - (void) strtoul (cp, (char **) &cp, 10); - if (*cp++ != ' ') - error (1, 0, "space expected in %s revision %s", - rcs->path, vnode->version); - count = strtoul (cp, (char **) &cp, 10); - if (*cp++ != '\012') - error (1, 0, "linefeed expected in %s revision %s", - rcs->path, vnode->version); - - if (op == 'd') - del += count; - else - { - add += count; - while (count != 0) - { - if (*cp == '\012') - --count; - else if (cp == value + vallen) - { - if (count != 1) - error (1, 0, "\ -premature end of value in %s revision %s", - rcs->path, vnode->version); - else - break; - } - ++cp; - } - } - } - } - - sprintf (buf, "%lu", add); - kv = getnode (); - kv->type = RCSFIELD; - kv->key = xstrdup (";add"); - kv->data = xstrdup (buf); - if (addnode (vnode->other, kv) != 0) - { - error (0, 0, - "\ -warning: duplicate key `%s' in version `%s' of RCS file `%s'", - key, vnode->version, rcs->path); - freenode (kv); - } - - sprintf (buf, "%lu", del); - kv = getnode (); - kv->type = RCSFIELD; - kv->key = xstrdup (";delete"); - kv->data = xstrdup (buf); - if (addnode (vnode->other, kv) != 0) - { - error (0, 0, - "\ -warning: duplicate key `%s' in version `%s' of RCS file `%s'", - key, vnode->version, rcs->path); - freenode (kv); - } - } - - /* We have found the "text" key which ends the data for - this revision. Break out of the loop and go on to the - next revision. */ - break; - } - } - - rcsbuf_cache (rcs, &rcsbuf); -} - - - -/* - * freercsnode - free up the info for an RCSNode - */ -void -freercsnode (rnodep) - RCSNode **rnodep; -{ - if (rnodep == NULL || *rnodep == NULL) - return; - - ((*rnodep)->refcount)--; - if ((*rnodep)->refcount != 0) - { - *rnodep = (RCSNode *) NULL; - return; - } - free ((*rnodep)->path); - if ((*rnodep)->head != (char *) NULL) - free ((*rnodep)->head); - if ((*rnodep)->branch != (char *) NULL) - free ((*rnodep)->branch); - free_rcsnode_contents (*rnodep); - free ((char *) *rnodep); - *rnodep = (RCSNode *) NULL; -} - -/* - * free_rcsnode_contents - free up the contents of an RCSNode without - * freeing the node itself, or the file name, or the head, or the - * path. This returns the RCSNode to the state it is in immediately - * after a call to RCS_parse. - */ -static void -free_rcsnode_contents (rnode) - RCSNode *rnode; -{ - dellist (&rnode->versions); - if (rnode->symbols != (List *) NULL) - dellist (&rnode->symbols); - if (rnode->symbols_data != (char *) NULL) - free (rnode->symbols_data); - if (rnode->expand != NULL) - free (rnode->expand); - if (rnode->other != (List *) NULL) - dellist (&rnode->other); - if (rnode->access != NULL) - free (rnode->access); - if (rnode->locks_data != NULL) - free (rnode->locks_data); - if (rnode->locks != (List *) NULL) - dellist (&rnode->locks); - if (rnode->comment != NULL) - free (rnode->comment); - if (rnode->desc != NULL) - free (rnode->desc); -} - -/* free_rcsvers_contents -- free up the contents of an RCSVers node, - but also free the pointer to the node itself. */ -/* Note: The `hardlinks' list is *not* freed, since it is merely a - pointer into the `hardlist' structure (defined in hardlink.c), and - that structure is freed elsewhere in the program. */ - -static void -free_rcsvers_contents (rnode) - RCSVers *rnode; -{ - if (rnode->branches != (List *) NULL) - dellist (&rnode->branches); - if (rnode->date != (char *) NULL) - free (rnode->date); - if (rnode->next != (char *) NULL) - free (rnode->next); - if (rnode->author != (char *) NULL) - free (rnode->author); - if (rnode->state != (char *) NULL) - free (rnode->state); - if (rnode->other != (List *) NULL) - dellist (&rnode->other); - if (rnode->other_delta != NULL) - dellist (&rnode->other_delta); - if (rnode->text != NULL) - freedeltatext (rnode->text); - free ((char *) rnode); -} - -/* - * rcsvers_delproc - free up an RCSVers type node - */ -static void -rcsvers_delproc (p) - Node *p; -{ - free_rcsvers_contents (p->data); -} - -/* These functions retrieve keys and values from an RCS file using a - buffer. We use this somewhat complex approach because it turns out - that for many common operations, CVS spends most of its time - reading keys, so it's worth doing some fairly hairy optimization. */ - -/* The number of bytes we try to read each time we need more data. */ - -#define RCSBUF_BUFSIZE (8192) - -/* The buffer we use to store data. This grows as needed. */ - -static char *rcsbuf_buffer = NULL; -static size_t rcsbuf_buffer_size = 0; - -/* Whether rcsbuf_buffer is in use. This is used as a sanity check. */ - -static int rcsbuf_inuse; - -/* Set up to start gathering keys and values from an RCS file. This - initializes RCSBUF. */ - -static void -rcsbuf_open (rcsbuf, fp, filename, pos) - struct rcsbuffer *rcsbuf; - FILE *fp; - const char *filename; - unsigned long pos; -{ -#ifdef HAVE_MMAP - void *p; - struct stat fs; - size_t mmap_off = 0; -#endif - - if (rcsbuf_inuse) - error (1, 0, "rcsbuf_open: internal error"); - rcsbuf_inuse = 1; - -#ifdef HAVE_MMAP - /* When we have mmap, it is much more efficient to let the system do the - * buffering and caching for us - */ - - if ( fstat (fileno(fp), &fs) < 0 ) - error ( 1, errno, "Could not stat RCS archive %s for mapping", filename ); - - if (pos) - { - size_t ps = getpagesize (); - mmap_off = ( pos / ps ) * ps; - } - - /* Map private here since this particular buffer is read only */ - p = mmap ( NULL, fs.st_size - mmap_off, PROT_READ | PROT_WRITE, - MAP_PRIVATE, fileno(fp), mmap_off ); - if (p != NULL && p != MAP_FAILED) - { - if (rcsbuf_buffer) free (rcsbuf_buffer); - rcsbuf_buffer = p; - rcsbuf_buffer_size = fs.st_size - mmap_off; - rcsbuf->mmapped = 1; - rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off; - rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off; - rcsbuf->pos = mmap_off; - } - else - { -#ifndef MMAP_FALLBACK_TEST - error (0, errno, "Could not map memory to RCS archive %s", filename); -#endif -#endif /* HAVE_MMAP */ - if (rcsbuf_buffer_size < RCSBUF_BUFSIZE) - expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE); - - rcsbuf->mmapped = 0; - rcsbuf->ptr = rcsbuf_buffer; - rcsbuf->ptrend = rcsbuf_buffer; - rcsbuf->pos = pos; -#ifdef HAVE_MMAP - } -#endif /* HAVE_MMAP */ - rcsbuf->fp = fp; - rcsbuf->filename = filename; - rcsbuf->vlen = 0; - rcsbuf->at_string = 0; - rcsbuf->embedded_at = 0; -} - -/* Stop gathering keys from an RCS file. */ - -static void -rcsbuf_close (rcsbuf) - struct rcsbuffer *rcsbuf; -{ - if (! rcsbuf_inuse) - error (1, 0, "rcsbuf_close: internal error"); -#ifdef HAVE_MMAP - if (rcsbuf->mmapped) - { - munmap ( rcsbuf_buffer, rcsbuf_buffer_size ); - rcsbuf_buffer = NULL; - rcsbuf_buffer_size = 0; - } -#endif - rcsbuf_inuse = 0; -} - -/* Read a key/value pair from an RCS file. This sets *KEYP to point - to the key, and *VALUEP to point to the value. A missing or empty - value is indicated by setting *VALUEP to NULL. - - This function returns 1 on success, or 0 on EOF. If there is an - error reading the file, or an EOF in an unexpected location, it - gives a fatal error. - - This sets *KEYP and *VALUEP to point to storage managed by - rcsbuf_getkey. Moreover, *VALUEP has not been massaged from the - RCS format: it may contain embedded whitespace and embedded '@' - 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; - char **keyp; - char **valp; -{ - 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. */ - assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size); - assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size); - - /* 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 (!rcsbuf->mmapped && 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. */ - assert (len <= RCSBUF_BUFSIZE); - - /* 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. */ - - *keyp = ptr; - - if (c != ';') - { - while (1) - { - ++ptr; - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (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 *KEYP points to the key in the buffer, C is the character - we found at the of the key, and PTR points to the location in - the buffer where we found C. We must set *PTR to \0 in order - to terminate the key. If the key ended with ';', then there is - no value. */ - - *ptr = '\0'; - ++ptr; - - if (c == ';') - { - *valp = NULL; - rcsbuf->ptr = ptr; - return 1; - } - - /* C must be whitespace. Skip whitespace between the key and the - value. If we find ';' now, there is no value. */ - - while (1) - { - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL); - if (ptr == NULL) - error (1, 0, "EOF while looking for value in RCS file %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - c = *ptr; - if (c == ';') - { - *valp = NULL; - rcsbuf->ptr = ptr + 1; - return 1; - } - if (! my_whitespace (c)) - break; - ++ptr; - } - - /* Now PTR points to the start of the value, and C is the first - character of the value. */ - - if (c != '@') - *valp = ptr; - else - { - char *pat; - size_t vlen; - - /* Optimize the common case of a value composed of a single - '@' string. */ - - rcsbuf->at_string = 1; - - ++ptr; - - *valp = 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, 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) - { - /* Note that we pass PAT, not PTR, here. */ - pat = rcsbuf_fill (rcsbuf, pat, keyp, valp); - 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 - *valp; - if (vlen == 0) - *valp = NULL; - rcsbuf->vlen = vlen; - - ptr = pat + 1; - } - - /* Certain keywords only have a '@' string. If there is no '@' - string, then the old getrcskey function assumed that they had - no value, and we do the same. */ - - { - char *k; - - k = *keyp; - if (STREQ (k, RCSDESC) - || STREQ (k, "text") - || STREQ (k, "log")) - { - if (c != '@') - *valp = NULL; - rcsbuf->ptr = ptr; - return 1; - } - } - - /* If we've already gathered a '@' string, try to skip whitespace - and find a ';'. */ - if (c == '@') - { - while (1) - { - char n; - - if (ptr >= 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; - } - n = *ptr; - if (n == ';') - { - /* We're done. We already set everything up for this - case above. */ - rcsbuf->ptr = ptr + 1; - return 1; - } - if (! my_whitespace (n)) - break; - ++ptr; - } - - /* The value extends past the '@' string. We need to undo the - '@' 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. */ - ((*valp)--)[rcsbuf->vlen++] = '@'; - } - - /* Here we have a value which is not a simple '@' string. We need - to gather up everything until the next ';', including any '@' - strings. *VALP points to the start of the value. If - RCSBUF->VLEN is not zero, then we have already read an '@' - string, and PTR points to the data following the '@' string. - Otherwise, PTR points to the start of the value. */ - - while (1) - { - char *start, *psemi, *pat; - - /* Find the ';' which must end the value. */ - start = ptr; - while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL) - { - int slen; - - /* 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. */ - slen = start - *valp; - ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp); - if (ptr == NULL) - error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename); - start = *valp + slen; - ptrend = rcsbuf->ptrend; - } - - /* See if there are any '@' strings in the value. */ - pat = memchr (start, '@', psemi - start); - - if (pat == NULL) - { - 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 - 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. */ - - rcsbuf->at_string = 1; - rcsbuf->embedded_at = -1; - - 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. */ - ptr = pat + 2; - } - - /* Here PAT points to the final '@' in the string. */ - ptr = pat + 1; - } - -#undef my_whitespace -} - -/* Read an RCS revision number from an RCS file. This sets *REVP to - point to the revision number; it will point to space that is - managed by the rcsbuf functions, and is only good until the next - call to rcsbuf_getkey or rcsbuf_getrevnum. - - This function returns 1 on success, or 0 on EOF. If there is an - error reading the file, or an EOF in an unexpected location, it - gives a fatal error. */ - -static int -rcsbuf_getrevnum (rcsbuf, revp) - struct rcsbuffer *rcsbuf; - char **revp; -{ - char *ptr, *ptrend; - char c; - - ptr = rcsbuf->ptr; - ptrend = rcsbuf->ptrend; - - *revp = NULL; - - /* 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 (! whitespace (c)) - break; - - ++ptr; - } - - if (! isdigit ((unsigned char) c) && c != '.') - error (1, 0, - "\ -unexpected '\\x%x' reading revision number in RCS file %s", - c, rcsbuf->filename); - - *revp = ptr; - - do - { - ++ptr; - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL); - if (ptr == NULL) - error (1, 0, - "unexpected EOF reading revision number in RCS file %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - c = *ptr; - } - while (isdigit ((unsigned char) c) || c == '.'); - - if (! whitespace (c)) - error (1, 0, "\ -unexpected '\\x%x' reading revision number in RCS file %s", - c, rcsbuf->filename); - - *ptr = '\0'; - - rcsbuf->ptr = ptr + 1; - - return 1; -} - -/* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF, - updating PTR and the PTREND field. If KEYP and *KEYP are not NULL, - then *KEYP points into the buffer, and must be adjusted if the - buffer is changed. Likewise for VALP. Returns the new value of - PTR, or NULL on error. */ - -static char * -rcsbuf_fill (rcsbuf, ptr, keyp, valp) - struct rcsbuffer *rcsbuf; - char *ptr; - char **keyp; - char **valp; -{ - int got; - - if (rcsbuf->mmapped) - return NULL; - - if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size) - { - int poff, peoff, koff, voff; - - poff = ptr - rcsbuf_buffer; - peoff = rcsbuf->ptrend - 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); - - ptr = rcsbuf_buffer + poff; - rcsbuf->ptrend = rcsbuf_buffer + peoff; - if (keyp != NULL) - *keyp = rcsbuf_buffer + koff; - if (valp != NULL) - *valp = rcsbuf_buffer + voff; - } - - got = fread (rcsbuf->ptrend, 1, RCSBUF_BUFSIZE, rcsbuf->fp); - if (got == 0) - { - if (ferror (rcsbuf->fp)) - error (1, errno, "cannot read %s", rcsbuf->filename); - return NULL; - } - - rcsbuf->ptrend += got; - - 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. */ - -static char * -rcsbuf_valcopy (rcsbuf, val, polish, lenp) - struct rcsbuffer *rcsbuf; - char *val; - int polish; - size_t *lenp; -{ - size_t vlen; - int embedded_at; - char *ret; - - if (val == NULL) - { - if (lenp != NULL) - *lenp = 0; - return NULL; - } - - vlen = rcsbuf->vlen; - embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at; - - ret = xmalloc (vlen - embedded_at + 1); - - if (rcsbuf->at_string ? embedded_at == 0 : ! polish) - { - /* No special action to take. */ - memcpy (ret, val, vlen + 1); - if (lenp != NULL) - *lenp = vlen; - return ret; - } - - rcsbuf_valpolish_internal (rcsbuf, ret, val, lenp); - return ret; -} - -/* Polish the value VAL returned by rcsbuf_getkey. The POLISH - parameter is non-zero if multiple embedded whitespace characters - should be compressed into a single whitespace character. Note that - leading and trailing whitespace was already removed by - rcsbuf_getkey. Within an '@' string, pairs of '@' characters are - compressed into a single '@' character regardless of the value of - POLISH. If LENP is not NULL, set *LENP to the length of the value. */ - -static void -rcsbuf_valpolish (rcsbuf, val, polish, lenp) - struct rcsbuffer *rcsbuf; - char *val; - int polish; - size_t *lenp; -{ - if (val == NULL) - { - if (lenp != NULL) - *lenp= 0; - return; - } - - if (rcsbuf->at_string ? rcsbuf->embedded_at == 0 : ! polish) - { - /* No special action to take. */ - if (lenp != NULL) - *lenp = rcsbuf->vlen; - return; - } - - rcsbuf_valpolish_internal (rcsbuf, val, val, lenp); -} - -/* Internal polishing routine, called from rcsbuf_valcopy and - rcsbuf_valpolish. */ - -static void -rcsbuf_valpolish_internal (rcsbuf, to, from, lenp) - struct rcsbuffer *rcsbuf; - char *to; - const char *from; - size_t *lenp; -{ - size_t len; - - len = rcsbuf->vlen; - - if (! rcsbuf->at_string) - { - char *orig_to; - size_t clen; - - orig_to = to; - - for (clen = len; clen > 0; ++from, --clen) - { - char c; - - c = *from; - if (whitespace (c)) - { - /* Note that we know that clen can not drop to zero - while we have whitespace, because we know there is - no trailing whitespace. */ - while (whitespace (from[1])) - { - ++from; - --clen; - } - c = ' '; - } - *to++ = c; - } - - *to = '\0'; - - if (lenp != NULL) - *lenp = to - orig_to; - } - else - { - const char *orig_from; - char *orig_to; - int embedded_at; - size_t clen; - - orig_from = from; - orig_to = to; - - embedded_at = rcsbuf->embedded_at; - assert (embedded_at > 0); - - if (lenp != NULL) - *lenp = len - embedded_at; - - for (clen = len; clen > 0; ++from, --clen) - { - char c; - - c = *from; - *to++ = c; - if (c == '@') - { - ++from; - - /* Sanity check. - * - * FIXME: I restored this to an abort from an assert based on - * advice from Larry Jones that asserts should not be used to - * confirm the validity of an RCS file... This leaves two - * issues here: 1) I am uncertain that the fact that we will - * only find double '@'s hasn't already been confirmed; and: - * 2) If this is the proper place to spot the error in the RCS - * file, then we should print a much clearer error here for the - * user!!!!!!! - * - * - DRP - */ - if (*from != '@' || clen == 0) - abort (); - - --clen; - - --embedded_at; - if (embedded_at == 0) - { - /* We've found all the embedded '@' characters. - We can just memcpy the rest of the buffer after - this '@' character. */ - if (orig_to != orig_from) - memcpy (to, from + 1, clen - 1); - else - memmove (to, from + 1, clen - 1); - from += clen; - to += clen - 1; - break; - } - } - } - - /* Sanity check. */ - assert (from == orig_from + len - && to == orig_to + (len - rcsbuf->embedded_at)); - - *to = '\0'; - } -} - -#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, "invalid 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, "invalid 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 -rcsbuf_ftell (rcsbuf) - struct rcsbuffer *rcsbuf; -{ - return rcsbuf->pos + (rcsbuf->ptr - rcsbuf_buffer); -} - -/* Return a pointer to any data buffered for RCSBUF, along with the - length. */ - -static void -rcsbuf_get_buffered (rcsbuf, datap, lenp) - struct rcsbuffer *rcsbuf; - char **datap; - size_t *lenp; -{ - *datap = rcsbuf->ptr; - *lenp = rcsbuf->ptrend - rcsbuf->ptr; -} - -/* CVS optimizes by quickly reading some header information from a - file. If it decides it needs to do more with the file, it reopens - it. We speed that up here by maintaining a cache of a single open - file, to save the time it takes to reopen the file in the common - case. */ - -static RCSNode *cached_rcs; -static struct rcsbuffer cached_rcsbuf; - -/* Cache RCS and RCSBUF. This takes responsibility for closing - RCSBUF->FP. */ - -static void -rcsbuf_cache (rcs, rcsbuf) - RCSNode *rcs; - struct rcsbuffer *rcsbuf; -{ - if (cached_rcs != NULL) - rcsbuf_cache_close (); - cached_rcs = rcs; - ++rcs->refcount; - cached_rcsbuf = *rcsbuf; -} - -/* If there is anything in the cache, close it. */ - -static void -rcsbuf_cache_close () -{ - if (cached_rcs != NULL) - { - rcsbuf_close (&cached_rcsbuf); - if (fclose (cached_rcsbuf.fp) != 0) - error (0, errno, "cannot close %s", cached_rcsbuf.filename); - freercsnode (&cached_rcs); - cached_rcs = NULL; - } -} - -/* Open an rcsbuffer for RCS, getting it from the cache if possible. - Set *FPP to the file, and *RCSBUFP to the rcsbuf. The file should - be put at position POS. */ - -static void -rcsbuf_cache_open (rcs, pos, pfp, prcsbuf) - RCSNode *rcs; - long pos; - FILE **pfp; - struct rcsbuffer *prcsbuf; -{ - if (cached_rcs == rcs && !cached_rcsbuf.mmapped) - { - if (rcsbuf_ftell (&cached_rcsbuf) != pos) - { - if (fseek (cached_rcsbuf.fp, pos, SEEK_SET) != 0) - error (1, 0, "cannot fseek RCS file %s", - cached_rcsbuf.filename); - cached_rcsbuf.ptr = rcsbuf_buffer; - cached_rcsbuf.ptrend = rcsbuf_buffer; - cached_rcsbuf.pos = pos; - } - *pfp = cached_rcsbuf.fp; - - /* When RCS_parse opens a file using fopen_case, it frees the - filename which we cached in CACHED_RCSBUF and stores a new - file name in RCS->PATH. We avoid problems here by always - copying the filename over. FIXME: This is hackish. */ - cached_rcsbuf.filename = rcs->path; - - *prcsbuf = cached_rcsbuf; - - cached_rcs = NULL; - - /* Removing RCS from the cache removes a reference to it. */ - --rcs->refcount; - if (rcs->refcount <= 0) - error (1, 0, "rcsbuf_cache_open: internal error"); - } - else - { - /* FIXME: If these routines can be rewritten to not write to the - * rcs file buffer, there would be a considerably larger memory savings - * from using mmap since the shared file would never need be copied to - * process memory. - * - * If this happens, cached mmapped buffers would be usable, but don't - * forget to make sure rcs->pos < pos here... - */ - if (cached_rcs != NULL) - rcsbuf_cache_close (); - - *pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ); - if (*pfp == NULL) - error (1, 0, "unable to reopen `%s'", rcs->path); - if (pos != 0) - { - if (fseek (*pfp, pos, SEEK_SET) != 0) - error (1, 0, "cannot fseek RCS file %s", rcs->path); - } - rcsbuf_open (prcsbuf, *pfp, rcs->path, pos); - } -} - - -/* - * process the symbols list of the rcs file - */ -static void -do_symbols (list, val) - List *list; - char *val; -{ - Node *p; - char *cp = val; - char *tag, *rev; - - assert (cp); - - for (;;) - { - /* skip leading whitespace */ - while (whitespace (*cp)) - cp++; - - /* if we got to the end, we are done */ - if (*cp == '\0') - break; - - /* split it up into tag and rev */ - tag = cp; - cp = strchr (cp, ':'); - *cp++ = '\0'; - rev = cp; - while (!whitespace (*cp) && *cp != '\0') - cp++; - if (*cp != '\0') - *cp++ = '\0'; - - /* make a new node and add it to the list */ - p = getnode (); - p->key = xstrdup (tag); - p->data = xstrdup (rev); - (void) addnode (list, p); - } -} - -/* - * process the locks list of the rcs file - * Like do_symbols, but hash entries are keyed backwards: i.e. - * an entry like `user:rev' is keyed on REV rather than on USER. - */ -static void -do_locks (list, val) - List *list; - char *val; -{ - Node *p; - char *cp = val; - char *user, *rev; - - assert (cp); - - for (;;) - { - /* skip leading whitespace */ - while (whitespace (*cp)) - cp++; - - /* if we got to the end, we are done */ - if (*cp == '\0') - break; - - /* split it up into user and rev */ - user = cp; - cp = strchr (cp, ':'); - *cp++ = '\0'; - rev = cp; - while (!whitespace (*cp) && *cp != '\0') - cp++; - if (*cp != '\0') - *cp++ = '\0'; - - /* make a new node and add it to the list */ - p = getnode (); - p->key = xstrdup (rev); - p->data = xstrdup (user); - (void) addnode (list, p); - } -} - -/* - * process the branches list of a revision delta - */ -static void -do_branches (list, val) - List *list; - char *val; -{ - Node *p; - char *cp = val; - char *branch; - - for (;;) - { - /* skip leading whitespace */ - while (whitespace (*cp)) - cp++; - - /* if we got to the end, we are done */ - if (*cp == '\0') - break; - - /* find the end of this branch */ - branch = cp; - while (!whitespace (*cp) && *cp != '\0') - cp++; - if (*cp != '\0') - *cp++ = '\0'; - - /* make a new node and add it to the list */ - p = getnode (); - p->key = xstrdup (branch); - (void) addnode (list, p); - } -} - -/* - * Version Number - * - * Returns the requested version number of the RCS file, satisfying tags and/or - * dates, and walking branches, if necessary. - * - * The result is returned; null-string if error. - */ -char * -RCS_getversion (rcs, tag, date, force_tag_match, simple_tag) - RCSNode *rcs; - const char *tag; - const char *date; - int force_tag_match; - int *simple_tag; -{ - if (simple_tag != NULL) - *simple_tag = 0; - - /* make sure we have something to look at... */ - assert (rcs != NULL); - - if (tag && date) - { - char *branch, *rev; - - if (! RCS_nodeisbranch (rcs, tag)) - { - /* We can't get a particular date if the tag is not a - branch. */ - return NULL; - } - - /* Work out the branch. */ - if (! isdigit ((unsigned char) tag[0])) - branch = RCS_whatbranch (rcs, tag); - else - branch = xstrdup (tag); - - /* Fetch the revision of branch as of date. */ - rev = RCS_getdatebranch (rcs, date, branch); - free (branch); - return (rev); - } - else if (tag) - return RCS_gettag (rcs, tag, force_tag_match, simple_tag); - else if (date) - return RCS_getdate (rcs, date, force_tag_match); - else - return RCS_head (rcs); - -} - - - -/* - * Get existing revision number corresponding to tag or revision. - * Similar to RCS_gettag but less interpretation imposed. - * For example: - * -- If tag designates a magic branch, RCS_tag2rev - * returns the magic branch number. - * -- If tag is a branch tag, returns the branch number, not - * the revision of the head of the branch. - * If tag or revision is not valid or does not exist in file, - * return NULL. - */ -char * -RCS_tag2rev (rcs, tag) - RCSNode *rcs; - char *tag; -{ - char *rev, *pa, *pb; - int i; - - assert (rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - /* If a valid revision, try to look it up */ - if ( RCS_valid_rev (tag) ) - { - /* Make a copy so we can scribble on it */ - rev = xstrdup (tag); - - /* If revision exists, return the copy */ - if (RCS_exist_rev (rcs, tag)) - return rev; - - /* Nope, none such. If tag is not a branch we're done. */ - i = numdots (rev); - if ((i & 1) == 1 ) - { - pa = strrchr (rev, '.'); - if (i == 1 || *(pa-1) != RCS_MAGIC_BRANCH || *(pa-2) != '.') - { - free (rev); - error (1, 0, "revision `%s' does not exist", tag); - } - } - - /* Try for a real (that is, exists in the RCS deltas) branch - (RCS_exist_rev just checks for real revisions and revisions - which have tags pointing to them). */ - pa = RCS_getbranch (rcs, rev, 1); - if (pa != NULL) - { - free (pa); - return rev; - } - - /* Tag is branch, but does not exist, try corresponding - * magic branch tag. - * - * FIXME: assumes all magic branches are of - * form "n.n.n ... .0.n". I'll fix if somebody can - * send me a method to get a magic branch tag with - * the 0 in some other position -- <dan@gasboy.com> - */ - pa = strrchr (rev, '.'); - if (!pa) - /* This might happen, for instance, if an RCS file only contained - * revisions 2.x and higher, and REV == "1". - */ - error (1, 0, "revision `%s' does not exist", tag); - - pb = xmalloc (strlen (rev) + 3); - *pa++ = 0; - (void) sprintf (pb, "%s.%d.%s", rev, RCS_MAGIC_BRANCH, pa); - free (rev); - rev = pb; - if (RCS_exist_rev (rcs, rev)) - return rev; - error (1, 0, "revision `%s' does not exist", tag); - } - - - RCS_check_tag (tag); /* exit if not a valid tag */ - - /* If tag is "HEAD", special case to get head RCS revision */ - if (tag && STREQ (tag, TAG_HEAD)) - return (RCS_head (rcs)); - - /* If valid tag let translate_symtag say yea or nay. */ - rev = translate_symtag (rcs, tag); - - if (rev) - return rev; - - /* Trust the caller to print warnings. */ - return NULL; -} - -/* - * Find the revision for a specific tag. - * If force_tag_match is set, return NULL if an exact match is not - * possible otherwise return RCS_head (). We are careful to look for - * and handle "magic" revisions specially. - * - * If the matched tag is a branch tag, find the head of the branch. - * - * Returns pointer to newly malloc'd string, or NULL. - */ -char * -RCS_gettag (rcs, symtag, force_tag_match, simple_tag) - RCSNode *rcs; - const char *symtag; - int force_tag_match; - int *simple_tag; -{ - char *tag; - - if (simple_tag != NULL) - *simple_tag = 0; - - /* make sure we have something to look at... */ - assert (rcs != NULL); - - /* XXX this is probably not necessary, --jtc */ - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - /* If symtag is "HEAD", special case to get head RCS revision */ - if (symtag && STREQ (symtag, TAG_HEAD)) -#if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */ - if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC)) - return ((char *) NULL); /* head request for removed file */ - else -#endif - return RCS_head (rcs); - - if (!isdigit ((unsigned char) symtag[0])) - { - char *version; - - /* If we got a symbolic tag, resolve it to a numeric */ - version = translate_symtag (rcs, symtag); - if (version != NULL) - { - int dots; - char *magic, *branch, *cp; - - tag = version; - - /* - * If this is a magic revision, we turn it into either its - * physical branch equivalent (if one exists) or into - * its base revision, which we assume exists. - */ - dots = numdots (tag); - if (dots > 2 && (dots & 1) != 0) - { - branch = strrchr (tag, '.'); - cp = branch++ - 1; - while (*cp != '.') - cp--; - - /* see if we have .magic-branch. (".0.") */ - magic = xmalloc (strlen (tag) + 1); - (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH); - if (strncmp (magic, cp, strlen (magic)) == 0) - { - /* it's magic. See if the branch exists */ - *cp = '\0'; /* turn it into a revision */ - (void) sprintf (magic, "%s.%s", tag, branch); - branch = RCS_getbranch (rcs, magic, 1); - free (magic); - if (branch != NULL) - { - free (tag); - return branch; - } - return tag; - } - free (magic); - } - } - else - { - /* The tag wasn't there, so return the head or NULL */ - if (force_tag_match) - return NULL; - else - return RCS_head (rcs); - } - } - else - tag = xstrdup (symtag); - - /* tag is always allocated and numeric now. */ - - /* - * numeric tag processing: - * 1) revision number - just return it - * 2) branch number - find head of branch - */ - - /* strip trailing dots */ - while (tag[strlen (tag) - 1] == '.') - tag[strlen (tag) - 1] = '\0'; - - if ((numdots (tag) & 1) == 0) - { - char *branch; - - /* we have a branch tag, so we need to walk the branch */ - branch = RCS_getbranch (rcs, tag, force_tag_match); - free (tag); - return branch; - } - else - { - Node *p; - - /* we have a revision tag, so make sure it exists */ - p = findnode (rcs->versions, tag); - if (p != NULL) - { - /* We have found a numeric revision for the revision tag. - To support expanding the RCS keyword Name, if - SIMPLE_TAG is not NULL, tell the the caller that this - is a simple tag which co will recognize. FIXME: Are - there other cases in which we should set this? In - particular, what if we expand RCS keywords internally - without calling co? */ - if (simple_tag != NULL) - *simple_tag = 1; - return tag; - } - else - { - /* The revision wasn't there, so return the head or NULL */ - free (tag); - if (force_tag_match) - return NULL; - else - return RCS_head (rcs); - } - } -} - -/* - * Return a "magic" revision as a virtual branch off of REV for the RCS file. - * A "magic" revision is one which is unique in the RCS file. By unique, I - * mean we return a revision which: - * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH) - * - has a revision component which is not an existing branch off REV - * - has a revision component which is not an existing magic revision - * - is an even-numbered revision, to avoid conflicts with vendor branches - * The first point is what makes it "magic". - * - * As an example, if we pass in 1.37 as REV, we will look for an existing - * branch called 1.37.2. If it did not exist, we would look for an - * existing symbolic tag with a numeric part equal to 1.37.0.2. If that - * didn't exist, then we know that the 1.37.2 branch can be reserved by - * creating a symbolic tag with 1.37.0.2 as the numeric part. - * - * This allows us to fork development with very little overhead -- just a - * symbolic tag is used in the RCS file. When a commit is done, a physical - * branch is dynamically created to hold the new revision. - * - * Note: We assume that REV is an RCS revision and not a branch number. - */ -static char *check_rev; -char * -RCS_magicrev (rcs, rev) - RCSNode *rcs; - char *rev; -{ - int rev_num; - char *xrev, *test_branch, *local_branch_num; - - xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */ - check_rev = xrev; - - local_branch_num = getenv("CVS_LOCAL_BRANCH_NUM"); - if (local_branch_num) - { - rev_num = atoi(local_branch_num); - if (rev_num < 2) - rev_num = 2; - else - rev_num &= ~1; - } - else - rev_num = 2; - - /* only look at even numbered branches */ - for ( ; ; rev_num += 2) - { - /* see if the physical branch exists */ - (void) sprintf (xrev, "%s.%d", rev, rev_num); - test_branch = RCS_getbranch (rcs, xrev, 1); - if (test_branch != NULL) /* it did, so keep looking */ - { - free (test_branch); - continue; - } - - /* now, create a "magic" revision */ - (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num); - - /* walk the symbols list to see if a magic one already exists */ - if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0) - continue; - - /* we found a free magic branch. Claim it as ours */ - return (xrev); - } -} - -/* - * walklist proc to look for a match in the symbols list. - * Returns 0 if the symbol does not match, 1 if it does. - */ -static int -checkmagic_proc (p, closure) - Node *p; - void *closure; -{ - if (STREQ (check_rev, p->data)) - return (1); - else - return (0); -} - -/* - * Given an RCSNode, returns non-zero if the specified revision number - * or symbolic tag resolves to a "branch" within the rcs file. - * - * FIXME: this is the same as RCS_nodeisbranch except for the special - * case for handling a null rcsnode. - */ -int -RCS_isbranch (rcs, rev) - RCSNode *rcs; - const char *rev; -{ - /* numeric revisions are easy -- even number of dots is a branch */ - if (isdigit ((unsigned char) *rev)) - return ((numdots (rev) & 1) == 0); - - /* assume a revision if you can't find the RCS info */ - if (rcs == NULL) - return (0); - - /* now, look for a match in the symbols list */ - return (RCS_nodeisbranch (rcs, rev)); -} - -/* - * Given an RCSNode, returns non-zero if the specified revision number - * or symbolic tag resolves to a "branch" within the rcs file. We do - * take into account any magic branches as well. - */ -int -RCS_nodeisbranch (rcs, rev) - RCSNode *rcs; - const char *rev; -{ - int dots; - char *version; - - assert (rcs != NULL); - - /* numeric revisions are easy -- even number of dots is a branch */ - if (isdigit ((unsigned char) *rev)) - return ((numdots (rev) & 1) == 0); - - version = translate_symtag (rcs, rev); - if (version == NULL) - return (0); - dots = numdots (version); - if ((dots & 1) == 0) - { - free (version); - return (1); - } - - /* got a symbolic tag match, but it's not a branch; see if it's magic */ - if (dots > 2) - { - char *magic; - char *branch = strrchr (version, '.'); - char *cp = branch - 1; - while (*cp != '.') - cp--; - - /* see if we have .magic-branch. (".0.") */ - magic = xmalloc (strlen (version) + 1); - (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH); - if (strncmp (magic, cp, strlen (magic)) == 0) - { - free (magic); - free (version); - return (1); - } - free (magic); - } - free (version); - return (0); -} - -/* - * Returns a pointer to malloc'ed memory which contains the branch - * for the specified *symbolic* tag. Magic branches are handled correctly. - */ -char * -RCS_whatbranch (rcs, rev) - RCSNode *rcs; - const char *rev; -{ - char *version; - int dots; - - /* assume no branch if you can't find the RCS info */ - if (rcs == NULL) - return ((char *) NULL); - - /* now, look for a match in the symbols list */ - version = translate_symtag (rcs, rev); - if (version == NULL) - return ((char *) NULL); - dots = numdots (version); - if ((dots & 1) == 0) - return (version); - - /* got a symbolic tag match, but it's not a branch; see if it's magic */ - if (dots > 2) - { - char *magic; - char *branch = strrchr (version, '.'); - char *cp = branch++ - 1; - while (*cp != '.') - cp--; - - /* see if we have .magic-branch. (".0.") */ - magic = xmalloc (strlen (version) + 1); - (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH); - if (strncmp (magic, cp, strlen (magic)) == 0) - { - /* yep. it's magic. now, construct the real branch */ - *cp = '\0'; /* turn it into a revision */ - (void) sprintf (magic, "%s.%s", version, branch); - free (version); - return (magic); - } - free (magic); - } - free (version); - return ((char *) NULL); -} - -/* - * Get the head of the specified branch. If the branch does not exist, - * return NULL or RCS_head depending on force_tag_match. - * Returns NULL or a newly malloc'd string. - */ -char * -RCS_getbranch (rcs, tag, force_tag_match) - RCSNode *rcs; - const char *tag; - int force_tag_match; -{ - Node *p, *head; - RCSVers *vn; - char *xtag; - char *nextvers; - char *cp; - - /* make sure we have something to look at... */ - assert (rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - /* find out if the tag contains a dot, or is on the trunk */ - cp = strrchr (tag, '.'); - - /* trunk processing is the special case */ - if (cp == NULL) - { - xtag = xmalloc (strlen (tag) + 1 + 1); /* +1 for an extra . */ - (void) strcpy (xtag, tag); - (void) strcat (xtag, "."); - for (cp = rcs->head; cp != NULL;) - { - if (strncmp (xtag, cp, strlen (xtag)) == 0) - break; - p = findnode (rcs->versions, cp); - if (p == NULL) - { - free (xtag); - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - vn = p->data; - cp = vn->next; - } - free (xtag); - if (cp == NULL) - { - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - return (xstrdup (cp)); - } - - /* if it had a `.', terminate the string so we have the base revision */ - *cp = '\0'; - - /* look up the revision this branch is based on */ - p = findnode (rcs->versions, tag); - - /* put the . back so we have the branch again */ - *cp = '.'; - - if (p == NULL) - { - /* if the base revision didn't exist, return head or NULL */ - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - - /* find the first element of the branch we are looking for */ - vn = p->data; - if (vn->branches == NULL) - return (NULL); - xtag = xmalloc (strlen (tag) + 1 + 1); /* 1 for the extra '.' */ - (void) strcpy (xtag, tag); - (void) strcat (xtag, "."); - head = vn->branches->list; - for (p = head->next; p != head; p = p->next) - if (strncmp (p->key, xtag, strlen (xtag)) == 0) - break; - free (xtag); - - if (p == head) - { - /* we didn't find a match so return head or NULL */ - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - - /* now walk the next pointers of the branch */ - nextvers = p->key; - do - { - p = findnode (rcs->versions, nextvers); - if (p == NULL) - { - /* a link in the chain is missing - return head or NULL */ - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - vn = p->data; - nextvers = vn->next; - } while (nextvers != NULL); - - /* we have the version in our hand, so go for it */ - return (xstrdup (vn->version)); -} - -/* Returns the head of the branch which REV is on. REV can be a - branch tag or non-branch tag; symbolic or numeric. - - Returns a newly malloc'd string. Returns NULL if a symbolic name - isn't found. */ - -char * -RCS_branch_head (rcs, rev) - RCSNode *rcs; - char *rev; -{ - char *num; - char *br; - char *retval; - - assert (rcs != NULL); - - if (RCS_nodeisbranch (rcs, rev)) - return RCS_getbranch (rcs, rev, 1); - - if (isdigit ((unsigned char) *rev)) - num = xstrdup (rev); - else - { - num = translate_symtag (rcs, rev); - if (num == NULL) - return NULL; - } - br = truncate_revnum (num); - retval = RCS_getbranch (rcs, br, 1); - free (br); - free (num); - return retval; -} - -/* Get the branch point for a particular branch, that is the first - revision on that branch. For example, RCS_getbranchpoint (rcs, - "1.3.2") will normally return "1.3.2.1". TARGET may be either a - branch number or a revision number; if a revnum, find the - branchpoint of the branch to which TARGET belongs. - - Return RCS_head if TARGET is on the trunk or if the root node could - not be found (this is sort of backwards from our behavior on a branch; - the rationale is that the return value is a revision from which you - can start walking the next fields and end up at TARGET). - Return NULL on error. */ - -static char * -RCS_getbranchpoint (rcs, target) - RCSNode *rcs; - char *target; -{ - char *branch, *bp; - Node *vp; - RCSVers *rev; - int dots, isrevnum, brlen; - - dots = numdots (target); - isrevnum = dots & 1; - - if (dots == 1) - /* TARGET is a trunk revision; return rcs->head. */ - return (RCS_head (rcs)); - - /* Get the revision number of the node at which TARGET's branch is - rooted. If TARGET is a branch number, lop off the last field; - if it's a revision number, lop off the last *two* fields. */ - branch = xstrdup (target); - bp = strrchr (branch, '.'); - if (bp == NULL) - error (1, 0, "%s: confused revision number %s", - rcs->path, target); - if (isrevnum) - while (*--bp != '.') - ; - *bp = '\0'; - - vp = findnode (rcs->versions, branch); - if (vp == NULL) - { - error (0, 0, "%s: can't find branch point %s", rcs->path, target); - free (branch); - return NULL; - } - rev = vp->data; - - *bp++ = '.'; - while (*bp && *bp != '.') - ++bp; - brlen = bp - branch; - - vp = rev->branches->list->next; - while (vp != rev->branches->list) - { - /* BRANCH may be a genuine branch number, e.g. `1.1.3', or - maybe a full revision number, e.g. `1.1.3.6'. We have - found our branch point if the first BRANCHLEN characters - of the revision number match, *and* if the following - character is a dot. */ - if (strncmp (vp->key, branch, brlen) == 0 && vp->key[brlen] == '.') - break; - vp = vp->next; - } - - free (branch); - if (vp == rev->branches->list) - { - error (0, 0, "%s: can't find branch point %s", rcs->path, target); - return NULL; - } - else - return (xstrdup (vp->key)); -} - -/* - * Get the head of the RCS file. If branch is set, this is the head of the - * branch, otherwise the real head. - * Returns NULL or a newly malloc'd string. - */ -char * -RCS_head (rcs) - RCSNode *rcs; -{ - /* make sure we have something to look at... */ - assert (rcs != NULL); - - /* - * NOTE: we call getbranch with force_tag_match set to avoid any - * possibility of recursion - */ - if (rcs->branch) - return (RCS_getbranch (rcs, rcs->branch, 1)); - else - return (xstrdup (rcs->head)); -} - -/* - * Get the most recent revision, based on the supplied date, but use some - * funky stuff and follow the vendor branch maybe - */ -char * -RCS_getdate (rcs, date, force_tag_match) - RCSNode *rcs; - const char *date; - int force_tag_match; -{ - char *cur_rev = NULL; - char *retval = NULL; - Node *p; - RCSVers *vers = NULL; - - /* make sure we have something to look at... */ - assert (rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - /* if the head is on a branch, try the branch first */ - if (rcs->branch != NULL) - { - retval = RCS_getdatebranch (rcs, date, rcs->branch); - if (retval != NULL) - return (retval); - } - - /* otherwise if we have a trunk, try it */ - if (rcs->head) - { - p = findnode (rcs->versions, rcs->head); - if (p == NULL) - { - error (0, 0, "%s: head revision %s doesn't exist", rcs->path, - rcs->head); - } - while (p != NULL) - { - /* if the date of this one is before date, take it */ - vers = p->data; - if (RCS_datecmp (vers->date, date) <= 0) - { - cur_rev = vers->version; - break; - } - - /* if there is a next version, find the node */ - if (vers->next != NULL) - p = findnode (rcs->versions, vers->next); - else - p = (Node *) NULL; - } - } - else - error (0, 0, "%s: no head revision", rcs->path); - - /* - * at this point, either we have the revision we want, or we have the - * first revision on the trunk (1.1?) in our hands, or we've come up - * completely empty - */ - - /* if we found what we're looking for, and it's not 1.1 return it */ - if (cur_rev != NULL) - { - if (! STREQ (cur_rev, "1.1")) - return (xstrdup (cur_rev)); - - /* This is 1.1; if the date of 1.1 is not the same as that for the - 1.1.1.1 version, then return 1.1. This happens when the first - version of a file is created by a regular cvs add and commit, - and there is a subsequent cvs import of the same file. */ - p = findnode (rcs->versions, "1.1.1.1"); - if (p) - { - char *date_1_1 = vers->date; - - assert (p->data != NULL); - - vers = p->data; - if (RCS_datecmp (vers->date, date_1_1) != 0) - return xstrdup ("1.1"); - } - } - - /* look on the vendor branch */ - retval = RCS_getdatebranch (rcs, date, CVSBRANCH); - - /* - * if we found a match, return it; otherwise, we return the first - * revision on the trunk or NULL depending on force_tag_match and the - * date of the first rev - */ - if (retval != NULL) - return (retval); - - if (vers && (!force_tag_match || RCS_datecmp (vers->date, date) <= 0)) - return xstrdup (vers->version); - else - return NULL; -} - - - -/* - * Look up the last element on a branch that was put in before the specified - * date (return the rev or NULL) - */ -static char * -RCS_getdatebranch (rcs, date, branch) - RCSNode *rcs; - const char *date; - const char *branch; -{ - char *cur_rev = NULL; - char *cp; - char *xbranch, *xrev; - Node *p; - RCSVers *vers; - - /* look up the first revision on the branch */ - xrev = xstrdup (branch); - cp = strrchr (xrev, '.'); - if (cp == NULL) - { - free (xrev); - return (NULL); - } - *cp = '\0'; /* turn it into a revision */ - - assert (rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - p = findnode (rcs->versions, xrev); - free (xrev); - if (p == NULL) - return (NULL); - vers = p->data; - - /* Tentatively use this revision, if it is early enough. */ - if (RCS_datecmp (vers->date, date) <= 0) - cur_rev = vers->version; - - /* If no branches list, return now. This is what happens if the branch - is a (magic) branch with no revisions yet. */ - if (vers->branches == NULL) - return xstrdup (cur_rev); - - /* walk the branches list looking for the branch number */ - xbranch = xmalloc (strlen (branch) + 1 + 1); /* +1 for the extra dot */ - (void) strcpy (xbranch, branch); - (void) strcat (xbranch, "."); - for (p = vers->branches->list->next; p != vers->branches->list; p = p->next) - if (strncmp (p->key, xbranch, strlen (xbranch)) == 0) - break; - free (xbranch); - if (p == vers->branches->list) - { - /* This is what happens if the branch is a (magic) branch with - no revisions yet. Similar to the case where vers->branches == - NULL, except here there was a another branch off the same - branchpoint. */ - return xstrdup (cur_rev); - } - - p = findnode (rcs->versions, p->key); - - /* walk the next pointers until you find the end, or the date is too late */ - while (p != NULL) - { - vers = p->data; - if (RCS_datecmp (vers->date, date) <= 0) - cur_rev = vers->version; - else - break; - - /* if there is a next version, find the node */ - if (vers->next != NULL) - p = findnode (rcs->versions, vers->next); - else - p = (Node *) NULL; - } - - /* Return whatever we found, which may be NULL. */ - return xstrdup (cur_rev); -} - - - -/* - * Compare two dates in RCS format. Beware the change in format on January 1, - * 2000, when years go from 2-digit to full format. - */ -int -RCS_datecmp (date1, date2) - const char *date1, *date2; -{ - int length_diff = strlen (date1) - strlen (date2); - - return length_diff ? length_diff : strcmp (date1, date2); -} - - - -/* Look up revision REV in RCS and return the date specified for the - revision minus FUDGE seconds (FUDGE will generally be one, so that the - logically previous revision will be found later, or zero, if we want - the exact date). - - The return value is the date being returned as a time_t, or (time_t)-1 - on error (previously was documented as zero on error; I haven't checked - the callers to make sure that they really check for (time_t)-1, but - the latter is what this function really returns). If DATE is non-NULL, - then it must point to MAXDATELEN characters, and we store the same - return value there in DATEFORM format. */ -time_t -RCS_getrevtime (rcs, rev, date, fudge) - RCSNode *rcs; - const char *rev; - char *date; - int fudge; -{ - char tdate[MAXDATELEN]; - struct tm xtm, *ftm; - time_t revdate = 0; - Node *p; - RCSVers *vers; - - /* make sure we have something to look at... */ - assert (rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - /* look up the revision */ - p = findnode (rcs->versions, rev); - if (p == NULL) - return (-1); - vers = p->data; - - /* split up the date */ - if (sscanf (vers->date, SDATEFORM, &xtm.tm_year, &xtm.tm_mon, - &xtm.tm_mday, &xtm.tm_hour, &xtm.tm_min, &xtm.tm_sec) != 6) - error (1, 0, "%s: invalid date for revision %s (%s)", rcs->path, - rev, vers->date); - - /* If the year is from 1900 to 1999, RCS files contain only two - digits, and sscanf gives us a year from 0-99. If the year is - 2000+, RCS files contain all four digits and we subtract 1900, - because the tm_year field should contain years since 1900. */ - - if (xtm.tm_year >= 100 && xtm.tm_year < 2000) - error (0, 0, "%s: non-standard date format for revision %s (%s)", - rcs->path, rev, vers->date); - if (xtm.tm_year >= 1900) - xtm.tm_year -= 1900; - - /* put the date in a form getdate can grok */ - (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", xtm.tm_mon, - xtm.tm_mday, xtm.tm_year + 1900, xtm.tm_hour, - xtm.tm_min, xtm.tm_sec); - - /* turn it into seconds since the epoch */ - revdate = get_date (tdate, (struct timeb *) NULL); - if (revdate != (time_t) -1) - { - revdate -= fudge; /* remove "fudge" seconds */ - if (date) - { - /* put an appropriate string into ``date'' if we were given one */ - ftm = gmtime (&revdate); - (void) sprintf (date, DATEFORM, - ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), - ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, - ftm->tm_min, ftm->tm_sec); - } - } - return revdate; -} - -List * -RCS_getlocks (rcs) - RCSNode *rcs; -{ - assert(rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - if (rcs->locks_data) { - rcs->locks = getlist (); - do_locks (rcs->locks, rcs->locks_data); - free(rcs->locks_data); - rcs->locks_data = NULL; - } - - return rcs->locks; -} - -List * -RCS_symbols(rcs) - RCSNode *rcs; -{ - assert(rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - if (rcs->symbols_data) { - rcs->symbols = getlist (); - do_symbols (rcs->symbols, rcs->symbols_data); - free(rcs->symbols_data); - rcs->symbols_data = NULL; - } - - return rcs->symbols; -} - -/* - * Return the version associated with a particular symbolic tag. - * Returns NULL or a newly malloc'd string. - */ -static char * -translate_symtag (rcs, tag) - RCSNode *rcs; - const char *tag; -{ - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - if (rcs->symbols != NULL) - { - Node *p; - - /* The symbols have already been converted into a list. */ - p = findnode (rcs->symbols, tag); - if (p == NULL) - return NULL; - - return xstrdup (p->data); - } - - if (rcs->symbols_data != NULL) - { - size_t len; - char *cp, *last; - - /* Look through the RCS symbols information. This is like - do_symbols, but we don't add the information to a list. In - most cases, we will only be called once for this file, so - generating the list is unnecessary overhead. */ - - len = strlen (tag); - cp = rcs->symbols_data; - /* Keeping track of LAST below isn't strictly necessary, now that tags - * should be parsed for validity before they are accepted, but tags - * with spaces used to cause the code below to loop indefintely, so - * I have corrected for that. Now, in the event that I missed - * something, the server cannot be hung. -DRP - */ - last = NULL; - while ((cp = strchr (cp, tag[0])) != NULL) - { - if (cp == last) break; - if ((cp == rcs->symbols_data || whitespace (cp[-1])) - && strncmp (cp, tag, len) == 0 - && cp[len] == ':') - { - char *v, *r; - - /* We found the tag. Return the version number. */ - - cp += len + 1; - v = cp; - while (! whitespace (*cp) && *cp != '\0') - ++cp; - r = xmalloc (cp - v + 1); - strncpy (r, v, cp - v); - r[cp - v] = '\0'; - return r; - } - - while (! whitespace (*cp) && *cp != '\0') - ++cp; - if (*cp == '\0') - break; - last = cp; - } - } - - return NULL; -} - -/* - * The argument ARG is the getopt remainder of the -k option specified on the - * command line. This function returns malloc'ed space that can be used - * directly in calls to RCS V5, with the -k flag munged correctly. - */ -char * -RCS_check_kflag (arg) - const char *arg; -{ - static const char *const keyword_usage[] = - { - "%s %s: invalid RCS keyword expansion mode\n", - "Valid expansion modes include:\n", - " -kkv\tGenerate keywords using the default form.\n", - " -kkvl\tLike -kkv, except locker's name inserted.\n", - " -kk\tGenerate only keyword names in keyword strings.\n", - " -kv\tGenerate only keyword values in keyword strings.\n", - " -ko\tGenerate the old keyword string (no changes from checked in file).\n", - " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n", - "(Specify the --help global option for a list of other help options)\n", - NULL, - }; - /* Big enough to hold any of the strings from kflags. */ - char karg[10]; - char const *const *cpp = NULL; - - if (arg) - { - for (cpp = kflags; *cpp != NULL; cpp++) - { - if (STREQ (arg, *cpp)) - break; - } - } - - if (arg == NULL || *cpp == NULL) - { - usage (keyword_usage); - } - - (void) sprintf (karg, "-k%s", *cpp); - return (xstrdup (karg)); -} - -/* - * Do some consistency checks on the symbolic tag... These should equate - * pretty close to what RCS checks, though I don't know for certain. - */ -void -RCS_check_tag (tag) - const char *tag; -{ - char *invalid = "$,.:;@"; /* invalid RCS tag characters */ - const char *cp; - - /* - * The first character must be an alphabetic letter. The remaining - * characters cannot be non-visible graphic characters, and must not be - * in the set of "invalid" RCS identifier characters. - */ - if (isalpha ((unsigned char) *tag)) - { - for (cp = tag; *cp; cp++) - { - if (!isgraph ((unsigned char) *cp)) - error (1, 0, "tag `%s' has non-visible graphic characters", - tag); - if (strchr (invalid, *cp)) - error (1, 0, "tag `%s' must not contain the characters `%s'", - tag, invalid); - } - } - else - error (1, 0, "tag `%s' must start with a letter", tag); -} - -/* - * TRUE if argument has valid syntax for an RCS revision or - * branch number. All characters must be digits or dots, first - * and last characters must be digits, and no two consecutive - * characters may be dots. - * - * Intended for classifying things, so this function doesn't - * call error. - */ -int -RCS_valid_rev (rev) - char *rev; -{ - char last, c; - last = *rev++; - if (!isdigit ((unsigned char) last)) - return 0; - while ((c = *rev++)) /* Extra parens placate -Wall gcc option */ - { - if (c == '.') - { - if (last == '.') - return 0; - continue; - } - last = c; - if (!isdigit ((unsigned char) c)) - return 0; - } - if (!isdigit ((unsigned char) last)) - return 0; - return 1; -} - -/* - * Return true if RCS revision with TAG is a dead revision. - */ -int -RCS_isdead (rcs, tag) - RCSNode *rcs; - const char *tag; -{ - Node *p; - RCSVers *version; - - assert (rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - p = findnode (rcs->versions, tag); - if (p == NULL) - return (0); - - version = p->data; - return (version->dead); -} - -/* Return the RCS keyword expansion mode. For example "b" for binary. - Returns a pointer into storage which is allocated and freed along with - the rest of the RCS information; the caller should not modify this - storage. Returns NULL if the RCS file does not specify a keyword - expansion mode; for all other errors, die with a fatal error. */ -char * -RCS_getexpand (rcs) - RCSNode *rcs; -{ - /* Since RCS_parsercsfile_i now reads expand, don't need to worry - about RCS_reparsercsfile. */ - assert (rcs != NULL); - return rcs->expand; -} - -/* Set keyword expansion mode to EXPAND. For example "b" for binary. */ -void -RCS_setexpand (rcs, expand) - RCSNode *rcs; - const char *expand; -{ - /* Since RCS_parsercsfile_i now reads expand, don't need to worry - about RCS_reparsercsfile. */ - assert (rcs != NULL); - if (rcs->expand != NULL) - free (rcs->expand); - rcs->expand = xstrdup (expand); -} - -/* RCS keywords, and a matching enum. */ -struct rcs_keyword -{ - const char *string; - size_t len; - int expandit; -}; -#define KEYWORD_INIT(s) (s), sizeof (s) - 1 -static struct rcs_keyword keywords[] = -{ - { KEYWORD_INIT ("Author"), 1 }, - { KEYWORD_INIT ("Date"), 1 }, - { KEYWORD_INIT ("CVSHeader"), 1 }, - { KEYWORD_INIT ("Header"), 1 }, - { KEYWORD_INIT ("Id"), 1 }, - { KEYWORD_INIT ("Locker"), 1 }, - { KEYWORD_INIT ("Log"), 1 }, - { KEYWORD_INIT ("Name"), 1 }, - { KEYWORD_INIT ("RCSfile"), 1 }, - { KEYWORD_INIT ("Revision"), 1 }, - { KEYWORD_INIT ("Source"), 1 }, - { KEYWORD_INIT ("State"), 1 }, - { NULL, 0, 0 }, - { NULL, 0, 0 } -}; -enum keyword -{ - KEYWORD_AUTHOR = 0, - KEYWORD_DATE, - KEYWORD_CVSHEADER, - KEYWORD_HEADER, - KEYWORD_ID, - KEYWORD_LOCKER, - KEYWORD_LOG, - KEYWORD_NAME, - KEYWORD_RCSFILE, - KEYWORD_REVISION, - KEYWORD_SOURCE, - KEYWORD_STATE, - KEYWORD_LOCALID -}; -enum keyword keyword_local = KEYWORD_ID; - -/* Convert an RCS date string into a readable string. This is like - the RCS date2str function. */ - -static char * -printable_date (rcs_date) - const char *rcs_date; -{ - int year, mon, mday, hour, min, sec; - char buf[100]; - - (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min, - &sec); - if (year < 1900) - year += 1900; - sprintf (buf, "%04d%c%02d%c%02d %02d:%02d:%02d", - year, datesep, mon, datesep, mday, hour, min, sec); - return xstrdup (buf); -} - -/* Escape the characters in a string so that it can be included in an - RCS value. */ - -static char * -escape_keyword_value (value, free_value) - const char *value; - int *free_value; -{ - char *ret, *t; - const char *s; - - for (s = value; *s != '\0'; s++) - { - char c; - - c = *s; - if (c == '\t' - || c == '\n' - || c == '\\' - || c == ' ' - || c == '$') - { - break; - } - } - - if (*s == '\0') - { - *free_value = 0; - return (char *) value; - } - - ret = xmalloc (strlen (value) * 4 + 1); - *free_value = 1; - - for (s = value, t = ret; *s != '\0'; s++, t++) - { - switch (*s) - { - default: - *t = *s; - break; - case '\t': - *t++ = '\\'; - *t = 't'; - break; - case '\n': - *t++ = '\\'; - *t = 'n'; - break; - case '\\': - *t++ = '\\'; - *t = '\\'; - break; - case ' ': - *t++ = '\\'; - *t++ = '0'; - *t++ = '4'; - *t = '0'; - break; - case '$': - *t++ = '\\'; - *t++ = '0'; - *t++ = '4'; - *t = '4'; - break; - } - } - - *t = '\0'; - - return ret; -} - -/* Expand RCS keywords in the memory buffer BUF of length LEN. This - applies to file RCS and version VERS. If NAME is not NULL, and is - not a numeric revision, then it is the symbolic tag used for the - checkout. EXPAND indicates how to expand the keywords. This - function sets *RETBUF and *RETLEN to the new buffer and length. - This function may modify the buffer BUF. If BUF != *RETBUF, then - RETBUF is a newly allocated buffer. */ - -static void -expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen) - RCSNode *rcs; - RCSVers *ver; - const char *name; - const char *log; - size_t loglen; - enum kflag expand; - char *buf; - size_t len; - char **retbuf; - size_t *retlen; -{ - struct expand_buffer - { - struct expand_buffer *next; - char *data; - size_t len; - int free_data; - } *ebufs = NULL; - struct expand_buffer *ebuf_last = NULL; - size_t ebuf_len = 0; - char *locker; - char *srch, *srch_next; - size_t srch_len; - - if (expand == KFLAG_O || expand == KFLAG_B) - { - *retbuf = buf; - *retlen = len; - return; - } - - /* If we are using -kkvl, dig out the locker information if any. */ - locker = NULL; - if (expand == KFLAG_KVL) - { - Node *lock; - lock = findnode (RCS_getlocks(rcs), ver->version); - if (lock != NULL) - locker = xstrdup (lock->data); - } - - /* RCS keywords look like $STRING$ or $STRING: VALUE$. */ - srch = buf; - srch_len = len; - while ((srch_next = memchr (srch, '$', srch_len)) != NULL) - { - char *s, *send; - size_t slen; - const struct rcs_keyword *keyword; - enum keyword kw; - char *value; - int free_value; - char *sub; - size_t sublen; - - srch_len -= (srch_next + 1) - srch; - srch = srch_next + 1; - - /* Look for the first non alphabetic character after the '$'. */ - send = srch + srch_len; - for (s = srch; s < send; s++) - if (! isalpha ((unsigned char) *s)) - break; - - /* If the first non alphabetic character is not '$' or ':', - then this is not an RCS keyword. */ - if (s == send || (*s != '$' && *s != ':')) - continue; - - /* See if this is one of the keywords. */ - slen = s - srch; - for (keyword = keywords; keyword->string != NULL; keyword++) - { - if (keyword->expandit - && keyword->len == slen - && strncmp (keyword->string, srch, slen) == 0) - { - break; - } - } - if (keyword->string == NULL) - continue; - - kw = (enum keyword) (keyword - keywords); - - /* If the keyword ends with a ':', then the old value consists - of the characters up to the next '$'. If there is no '$' - before the end of the line, though, then this wasn't an RCS - keyword after all. */ - if (*s == ':') - { - for (; s < send; s++) - if (*s == '$' || *s == '\n') - break; - if (s == send || *s != '$') - continue; - } - - /* At this point we must replace the string from SRCH to S - with the expansion of the keyword KW. */ - - /* Get the value to use. */ - free_value = 0; - if (expand == KFLAG_K) - value = NULL; - else - { - switch (kw) - { - default: - abort (); - - case KEYWORD_AUTHOR: - value = ver->author; - break; - - case KEYWORD_DATE: - value = printable_date (ver->date); - free_value = 1; - break; - - case KEYWORD_CVSHEADER: - case KEYWORD_HEADER: - case KEYWORD_ID: - case KEYWORD_LOCALID: - { - const char *path; - int free_path; - char *date; - char *old_path; - - old_path = NULL; - if (kw == KEYWORD_HEADER || - (kw == KEYWORD_LOCALID && - keyword_local == KEYWORD_HEADER)) - path = rcs->path; - else if (kw == KEYWORD_CVSHEADER || - (kw == KEYWORD_LOCALID && - keyword_local == KEYWORD_CVSHEADER)) - path = getfullCVSname(rcs->path, &old_path); - else - path = last_component (rcs->path); - path = escape_keyword_value (path, &free_path); - date = printable_date (ver->date); - value = xmalloc (strlen (path) - + strlen (ver->version) - + strlen (date) - + strlen (ver->author) - + strlen (ver->state) - + (locker == NULL ? 0 : strlen (locker)) - + 20); - - sprintf (value, "%s %s %s %s %s%s%s", - path, ver->version, date, ver->author, - ver->state, - locker != NULL ? " " : "", - locker != NULL ? locker : ""); - if (free_path) - /* If free_path is set then we know we allocated path - * and we can discard the const. - */ - free ((char *)path); - if (old_path) - free (old_path); - free (date); - free_value = 1; - } - break; - - case KEYWORD_LOCKER: - value = locker; - break; - - case KEYWORD_LOG: - case KEYWORD_RCSFILE: - value = escape_keyword_value (last_component (rcs->path), - &free_value); - break; - - case KEYWORD_NAME: - if (name != NULL && ! isdigit ((unsigned char) *name)) - value = (char *) name; - else - value = NULL; - break; - - case KEYWORD_REVISION: - value = ver->version; - break; - - case KEYWORD_SOURCE: - value = escape_keyword_value (rcs->path, &free_value); - break; - - case KEYWORD_STATE: - value = ver->state; - break; - } - } - - sub = xmalloc (keyword->len - + (value == NULL ? 0 : strlen (value)) - + 10); - if (expand == KFLAG_V) - { - /* Decrement SRCH and increment S to remove the $ - characters. */ - --srch; - ++srch_len; - ++s; - sublen = 0; - } - else - { - strcpy (sub, keyword->string); - sublen = strlen (keyword->string); - if (expand != KFLAG_K) - { - sub[sublen] = ':'; - sub[sublen + 1] = ' '; - sublen += 2; - } - } - if (value != NULL) - { - strcpy (sub + sublen, value); - sublen += strlen (value); - } - if (expand != KFLAG_V && expand != KFLAG_K) - { - sub[sublen] = ' '; - ++sublen; - sub[sublen] = '\0'; - } - - if (free_value) - free (value); - - /* The Log keyword requires special handling. This behaviour - is taken from RCS 5.7. The special log message is what RCS - 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)) - { - char *start; - char *leader; - size_t leader_len, leader_sp_len; - const char *logend; - const char *snl; - int cnl; - char *date; - const char *sl; - - /* We are going to insert the trailing $ ourselves, before - the log message, so we must remove it from S, if we - haven't done so already. */ - 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') - --start; - - /* Copy the start of the line to use as a comment leader. */ - leader_len = srch - start; - if (expand != KFLAG_V) - --leader_len; - leader = xmalloc (leader_len); - memcpy (leader, start, leader_len); - leader_sp_len = leader_len; - while (leader_sp_len > 0 && leader[leader_sp_len - 1] == ' ') - --leader_sp_len; - - /* RCS does some checking for an old style of Log here, - but we don't bother. RCS issues a warning if it - changes anything. */ - - /* Count the number of newlines in the log message so that - we know how many copies of the leader we will need. */ - cnl = 0; - logend = log + loglen; - for (snl = log; snl < logend; snl++) - if (*snl == '\n') - ++cnl; - - /* If the log message did not end in a newline, increment - * the newline count so we have space for the extra leader. - * Failure to do so results in a buffer overrun. - */ - if (loglen && snl[-1] != '\n') - ++cnl; - - date = printable_date (ver->date); - sub = xrealloc (sub, - (sublen - + sizeof "Revision" - + strlen (ver->version) - + strlen (date) - + strlen (ver->author) - + loglen - /* Use CNL + 2 below: One leader for each log - * line, plus the Revision/Author/Date line, - * plus a trailing blank line. - */ - + (cnl + 2) * leader_len - + 20)); - if (expand != KFLAG_V) - { - sub[sublen] = '$'; - ++sublen; - } - sub[sublen] = '\n'; - ++sublen; - memcpy (sub + sublen, leader, leader_len); - sublen += leader_len; - sprintf (sub + sublen, "Revision %s %s %s\n", - ver->version, date, ver->author); - sublen += strlen (sub + sublen); - free (date); - - sl = log; - while (sl < logend) - { - if (*sl == '\n') - { - memcpy (sub + sublen, leader, leader_sp_len); - sublen += leader_sp_len; - sub[sublen] = '\n'; - ++sublen; - ++sl; - } - else - { - const char *slnl; - - memcpy (sub + sublen, leader, leader_len); - sublen += leader_len; - for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl) - ; - if (slnl < logend) - ++slnl; - memcpy (sub + sublen, sl, slnl - sl); - sublen += slnl - sl; - if (slnl == logend && slnl[-1] != '\n') - { - /* There was no EOL at the end of the log message. Add - * one. - */ - sub[sublen] = '\n'; - ++sublen; - } - sl = slnl; - } - } - - memcpy (sub + sublen, leader, leader_sp_len); - sublen += leader_sp_len; - - free (leader); - } - - /* Now SUB contains a string which is to replace the string - from SRCH to S. SUBLEN is the length of SUB. */ - - if (srch + sublen == s) - { - memcpy (srch, sub, sublen); - free (sub); - } - else - { - struct expand_buffer *ebuf; - - /* We need to change the size of the buffer. We build a - list of expand_buffer structures. Each expand_buffer - structure represents a portion of the final output. We - concatenate them back into a single buffer when we are - done. This minimizes the number of potentially large - buffer copies we must do. */ - - if (ebufs == NULL) - { - ebufs = (struct expand_buffer *) xmalloc (sizeof *ebuf); - ebufs->next = NULL; - ebufs->data = buf; - ebufs->free_data = 0; - ebuf_len = srch - buf; - ebufs->len = ebuf_len; - ebuf_last = ebufs; - } - else - { - assert (srch >= ebuf_last->data); - assert (srch <= ebuf_last->data + ebuf_last->len); - ebuf_len -= ebuf_last->len - (srch - ebuf_last->data); - ebuf_last->len = srch - ebuf_last->data; - } - - ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf); - ebuf->data = sub; - ebuf->len = sublen; - ebuf->free_data = 1; - ebuf->next = NULL; - ebuf_last->next = ebuf; - ebuf_last = ebuf; - ebuf_len += sublen; - - ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf); - ebuf->data = s; - ebuf->len = srch_len - (s - srch); - ebuf->free_data = 0; - ebuf->next = NULL; - ebuf_last->next = ebuf; - ebuf_last = ebuf; - ebuf_len += srch_len - (s - srch); - } - - srch_len -= (s - srch); - srch = s; - } - - if (locker != NULL) - free (locker); - - if (ebufs == NULL) - { - *retbuf = buf; - *retlen = len; - } - else - { - char *ret; - - ret = xmalloc (ebuf_len); - *retbuf = ret; - *retlen = ebuf_len; - while (ebufs != NULL) - { - struct expand_buffer *next; - - memcpy (ret, ebufs->data, ebufs->len); - ret += ebufs->len; - if (ebufs->free_data) - free (ebufs->data); - next = ebufs->next; - free (ebufs); - ebufs = next; - } - } -} - - - -/* Check out a revision from an RCS file. - - If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero - or more times with the contents of the file. CALLERDAT is passed, - uninterpreted, to PFN. (The current code will always call PFN - exactly once for a non empty file; however, the current code - assumes that it can hold the entire file contents in memory, which - is not a good assumption, and might change in the future). - - Otherwise, if WORKFILE is not NULL, check out the revision to - WORKFILE. However, if WORKFILE is not NULL, and noexec is set, - then don't do anything. - - Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If - SOUT is RUN_TTY, then write the contents of the revision to - standard output. When using SOUT, the output is generally a - temporary file; don't bother to get the file modes correct. When - NOEXEC is set, WORKFILEs are not written but SOUTs are. - - REV is the numeric revision to check out. It may be NULL, which - means to check out the head of the default branch. - - If NAMETAG is not NULL, and is not a numeric revision, then it is - the tag that should be used when expanding the RCS Name keyword. - - OPTIONS is a string such as "-kb" or "-kv" for keyword expansion - options. It may be NULL to use the default expansion mode of the - file, typically "-kkv". - - On an error which prevented checking out the file, either print a - nonfatal error and return 1, or give a fatal error. On success, - return 0. */ - -/* This function mimics the behavior of `rcs co' almost exactly. The - chief difference is in its support for preserving file ownership, - permissions, and special files across checkin and checkout -- see - comments in RCS_checkin for some issues about this. -twp */ - -int -RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) - RCSNode *rcs; - const char *workfile; - const char *rev; - const char *nametag; - const char *options; - const char *sout; - RCSCHECKOUTPROC pfn; - void *callerdat; -{ - int free_rev = 0; - enum kflag expand; - FILE *fp; - FILE *ofp = NULL; - struct stat sb; - struct rcsbuffer rcsbuf; - char *key; - char *value; - size_t len; - int free_value = 0; - char *log = NULL; - size_t loglen = 0; - Node *vp = NULL; -#ifdef PRESERVE_PERMISSIONS_SUPPORT - uid_t rcs_owner = (uid_t) -1; - gid_t rcs_group = (gid_t) -1; - mode_t rcs_mode; - int change_rcs_owner_or_group = 0; - int change_rcs_mode = 0; - int special_file = 0; - unsigned long devnum_long; - dev_t devnum = 0; -#endif - - if (trace) - { - (void) fprintf (stderr, "%s-> RCS_checkout (%s, %s, %s, %s, %s)\n", -#ifdef SERVER_SUPPORT - server_active ? "S" : " ", -#else - "", -#endif - rcs->path, - rev != NULL ? rev : "", - nametag != NULL ? nametag : "", - options != NULL ? options : "", - (pfn != NULL ? "(function)" - : (workfile != NULL - ? workfile - : (sout != RUN_TTY ? sout : "(stdout)")))); - } - - assert (rev == NULL || isdigit ((unsigned char) *rev)); - - if (noexec && !server_active && workfile != NULL) - return 0; - - assert (sout == RUN_TTY || workfile == NULL); - assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL)); - - /* Some callers, such as Checkin or remove_file, will pass us a - branch. */ - if (rev != NULL && (numdots (rev) & 1) == 0) - { - rev = RCS_getbranch (rcs, rev, 1); - if (rev == NULL) - error (1, 0, "internal error: bad branch tag in checkout"); - free_rev = 1; - } - - if (rev == NULL || STREQ (rev, rcs->head)) - { - int gothead; - - /* We want the head revision. Try to read it directly. */ - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, &fp, &rcsbuf); - else - rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf); - - gothead = 0; - if (! rcsbuf_getrevnum (&rcsbuf, &key)) - error (1, 0, "unexpected EOF reading %s", rcs->path); - - if (!STREQ (rcs->head, key)) - error (1, 0, "Expected head revision %s, found %s.", - rcs->head, key); - - while (rcsbuf_getkey (&rcsbuf, &key, &value)) - { - if (STREQ (key, "log")) - { - if (log) - { - error (0, 0, -"Duplicate log keyword found for head revision in RCS file."); - free (log); - } - log = rcsbuf_valcopy (&rcsbuf, value, 0, &loglen); - } - else if (STREQ (key, "text")) - { - gothead = 1; - break; - } - } - - if (! gothead) - { - error (0, 0, "internal error: cannot find head text"); - if (free_rev) - /* It's okay to discard the const when free_rev is set, because - * we know we allocated it in this function. - */ - free ((char *)rev); - return 1; - } - - rcsbuf_valpolish (&rcsbuf, value, 0, &len); - - if (fstat (fileno (fp), &sb) < 0) - error (1, errno, "cannot fstat %s", rcs->path); - - rcsbuf_cache (rcs, &rcsbuf); - } - else - { - struct rcsbuffer *rcsbufp; - - /* It isn't the head revision of the trunk. We'll need to - walk through the deltas. */ - - fp = NULL; - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, &fp, &rcsbuf); - - if (fp == NULL) - { - /* If RCS_deltas didn't close the file, we could use fstat - here too. Probably should change it thusly.... */ - if (stat (rcs->path, &sb) < 0) - error (1, errno, "cannot stat %s", rcs->path); - rcsbufp = NULL; - } - else - { - if (fstat (fileno (fp), &sb) < 0) - error (1, errno, "cannot fstat %s", rcs->path); - rcsbufp = &rcsbuf; - } - - RCS_deltas (rcs, fp, rcsbufp, rev, RCS_FETCH, &value, &len, - &log, &loglen); - free_value = 1; - } - - /* If OPTIONS is NULL or the empty string, then the old code would - invoke the RCS co program with no -k option, which means that - co would use the string we have stored in rcs->expand. */ - if ((options == NULL || options[0] == '\0') && rcs->expand == NULL) - expand = KFLAG_KV; - else - { - const char *ouroptions; - const char * const *cpp; - - if (options != NULL && options[0] != '\0') - { - assert (options[0] == '-' && options[1] == 'k'); - ouroptions = options + 2; - } - else - ouroptions = rcs->expand; - - for (cpp = kflags; *cpp != NULL; cpp++) - if (STREQ (*cpp, ouroptions)) - break; - - if (*cpp != NULL) - expand = (enum kflag) (cpp - kflags); - else - { - error (0, 0, - "internal error: unsupported substitution string -k%s", - ouroptions); - expand = KFLAG_KV; - } - } - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - /* Handle special files and permissions, if that is desired. */ - if (preserve_perms) - { - RCSVers *vers; - Node *info; - - vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev); - if (vp == NULL) - error (1, 0, "internal error: no revision information for %s", - rev == NULL ? rcs->head : rev); - vers = vp->data; - - /* First we look for symlinks, which are simplest to handle. */ - info = findnode (vers->other_delta, "symlink"); - if (info != NULL) - { - char *dest; - - if (pfn != NULL || (workfile == NULL && sout == RUN_TTY)) - error (1, 0, "symbolic link %s:%s cannot be piped", - rcs->path, vers->version); - if (workfile == NULL) - dest = sout; - else - dest = workfile; - - /* Remove `dest', just in case. It's okay to get ENOENT here, - since we just want the file not to be there. (TODO: decide - whether it should be considered an error for `dest' to exist - at this point. If so, the unlink call should be removed and - `symlink' should signal the error. -twp) */ - if (CVS_UNLINK (dest) < 0 && !existence_error (errno)) - error (1, errno, "cannot remove %s", dest); - if (symlink (info->data, dest) < 0) - error (1, errno, "cannot create symbolic link from %s to %s", - dest, (char *)info->data); - if (free_value) - free (value); - if (free_rev) - /* It's okay to discard the const when free_rev is set, because - * we know we allocated it in this function. - */ - free ((char *)rev); - return 0; - } - - /* Next, we look at this file's hardlinks field, and see whether - it is linked to any other file that has been checked out. - If so, we don't do anything else -- just link it to that file. - - If we are checking out a file to a pipe or temporary storage, - none of this should matter. Hence the `workfile != NULL' - wrapper around the whole thing. -twp */ - - if (workfile != NULL) - { - List *links = vers->hardlinks; - if (links != NULL) - { - Node *uptodate_link; - - /* For each file in the hardlinks field, check to see - if it exists, and if so, if it has been checked out - this iteration. When walklist returns, uptodate_link - should point to a hardlist node representing a file - in `links' which has recently been checked out, or - NULL if no file in `links' has yet been checked out. */ - - uptodate_link = NULL; - (void) walklist (links, find_checkedout_proc, &uptodate_link); - dellist (&links); - - /* If we've found a file that `workfile' is supposed to be - linked to, and it has been checked out since CVS was - invoked, then simply link workfile to that file and return. - - If one of these conditions is not met, then - workfile is the first one in its hardlink group to - be checked out, and we must continue with a full - checkout. */ - - if (uptodate_link != NULL) - { - struct hardlink_info *hlinfo = uptodate_link->data; - - if (link (uptodate_link->key, workfile) < 0) - error (1, errno, "cannot link %s to %s", - workfile, uptodate_link->key); - hlinfo->checked_out = 1; /* probably unnecessary */ - if (free_value) - free (value); - if (free_rev) - /* It's okay to discard the const when free_rev is set, - * because we know we allocated it in this function. - */ - free ((char *)rev); - return 0; - } - } - } - - info = findnode (vers->other_delta, "owner"); - if (info != NULL) - { - change_rcs_owner_or_group = 1; - rcs_owner = (uid_t) strtoul (info->data, NULL, 10); - } - info = findnode (vers->other_delta, "group"); - if (info != NULL) - { - change_rcs_owner_or_group = 1; - rcs_group = (gid_t) strtoul (info->data, NULL, 10); - } - info = findnode (vers->other_delta, "permissions"); - if (info != NULL) - { - change_rcs_mode = 1; - rcs_mode = (mode_t) strtoul (info->data, NULL, 8); - } - info = findnode (vers->other_delta, "special"); - if (info != NULL) - { - /* If the size of `devtype' changes, fix the sscanf call also */ - char devtype[16]; - - if (sscanf (info->data, "%15s %lu", - devtype, &devnum_long) < 2) - error (1, 0, "%s:%s has bad `special' newphrase %s", - workfile, vers->version, (char *)info->data); - devnum = devnum_long; - if (STREQ (devtype, "character")) - special_file = S_IFCHR; - else if (STREQ (devtype, "block")) - special_file = S_IFBLK; - else - error (0, 0, "%s is a special file of unsupported type `%s'", - workfile, (char *)info->data); - } - } -#endif /* PRESERVE_PERMISSIONS_SUPPORT */ - - if (expand != KFLAG_O && expand != KFLAG_B) - { - char *newvalue; - - /* Don't fetch the delta node again if we already have it. */ - if (vp == NULL) - { - vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev); - if (vp == NULL) - error (1, 0, "internal error: no revision information for %s", - rev == NULL ? rcs->head : rev); - } - - expand_keywords (rcs, vp->data, nametag, log, loglen, - expand, value, len, &newvalue, &len); - - if (newvalue != value) - { - if (free_value) - free (value); - value = newvalue; - free_value = 1; - } - } - - if (free_rev) - /* It's okay to discard the const when free_rev is set, because - * we know we allocated it in this function. - */ - free ((char *)rev); - - if (log != NULL) - { - free (log); - log = NULL; - } - - if (pfn != NULL) - { -#ifdef PRESERVE_PERMISSIONS_SUPPORT - if (special_file) - error (1, 0, "special file %s cannot be piped to anything", - rcs->path); -#endif - /* The PFN interface is very simple to implement right now, as - we always have the entire file in memory. */ - if (len != 0) - pfn (callerdat, value, len); - } -#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 - not RUN_TTY. */ - dest = workfile; - if (dest == NULL) - { - if (sout == RUN_TTY) - error (1, 0, "special file %s cannot be written to stdout", - rcs->path); - dest = sout; - } - - /* Unlink `dest', just in case. It's okay if this provokes a - ENOENT error. */ - if (CVS_UNLINK (dest) < 0 && existence_error (errno)) - error (1, errno, "cannot remove %s", dest); - 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 - { - /* Not a special file: write to WORKFILE or SOUT. */ - if (workfile == NULL) - { - if (sout == RUN_TTY) - ofp = stdout; - else - { - /* Symbolic links should be removed before replacement, so that - `fopen' doesn't follow the link and open the wrong file. */ - if (islink (sout)) - if (unlink_file (sout) < 0) - error (1, errno, "cannot remove %s", sout); - ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w"); - if (ofp == NULL) - error (1, errno, "cannot open %s", sout); - } - } - else - { - /* Output is supposed to go to WORKFILE, so we should open that - file. Symbolic links should be removed first (see above). */ - if (islink (workfile)) - if (unlink_file (workfile) < 0) - error (1, errno, "cannot remove %s", workfile); - - ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w"); - - /* If the open failed because the existing workfile was not - writable, try to chmod the file and retry the open. */ - if (ofp == NULL && errno == EACCES - && isfile (workfile) && !iswritable (workfile)) - { - xchmod (workfile, 1); - ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w"); - } - - if (ofp == NULL) - { - error (0, errno, "cannot open %s", workfile); - if (free_value) - free (value); - return 1; - } - } - - if (workfile == NULL && sout == RUN_TTY) - { - if (expand == KFLAG_B) - cvs_output_binary (value, len); - else - { - /* cvs_output requires the caller to check for zero - length. */ - if (len > 0) - cvs_output (value, len); - } - } - else - { - /* NT 4.0 is said to have trouble writing 2099999 bytes - (for example) in a single fwrite. So break it down - (there is no need to be writing that much at once - anyway; it is possible that LARGEST_FWRITE should be - somewhat larger for good performance, but for testing I - want to start with a small value until/unless a bigger - one proves useful). */ -#define LARGEST_FWRITE 8192 - size_t nleft = len; - size_t nstep = (len < LARGEST_FWRITE ? len : LARGEST_FWRITE); - char *p = value; - - while (nleft > 0) - { - if (fwrite (p, 1, nstep, ofp) != nstep) - { - error (0, errno, "cannot write %s", - (workfile != NULL - ? workfile - : (sout != RUN_TTY ? sout : "stdout"))); - if (free_value) - free (value); - return 1; - } - p += nstep; - nleft -= nstep; - if (nleft < nstep) - nstep = nleft; - } - } - } - - if (free_value) - free (value); - - if (workfile != NULL) - { - int ret; - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - if (!special_file && fclose (ofp) < 0) - { - error (0, errno, "cannot close %s", workfile); - return 1; - } - - if (change_rcs_owner_or_group) - { - if (chown (workfile, rcs_owner, rcs_group) < 0) - error (0, errno, "could not change owner or group of %s", - workfile); - } - - ret = chmod (workfile, - change_rcs_mode - ? rcs_mode - : sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH)); -#else - if (fclose (ofp) < 0) - { - error (0, errno, "cannot close %s", workfile); - return 1; - } - - ret = chmod (workfile, - sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH)); -#endif - if (ret < 0) - { - error (0, errno, "cannot change mode of file %s", - workfile); - } - } - else if (sout != RUN_TTY) - { - if ( -#ifdef PRESERVE_PERMISSIONS_SUPPORT - !special_file && -#endif - fclose (ofp) < 0) - { - error (0, errno, "cannot close %s", sout); - return 1; - } - } - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - /* If we are in the business of preserving hardlinks, then - mark this file as having been checked out. */ - if (preserve_perms && workfile != NULL) - update_hardlink_info (workfile); -#endif - - return 0; -} - -static RCSVers *RCS_findlock_or_tip PROTO ((RCSNode *rcs)); - -/* Find the delta currently locked by the user. From the `ci' man page: - - "If rev is omitted, ci tries to derive the new revision - number from the caller's last lock. If the caller has - locked the tip revision of a branch, the new revision is - appended to that branch. The new revision number is - obtained by incrementing the tip revision number. If the - caller locked a non-tip revision, a new branch is started - at that revision by incrementing the highest branch number - at that revision. The default initial branch and level - numbers are 1. - - If rev is omitted and the caller has no lock, but owns the - file and locking is not set to strict, then the revision - is appended to the default branch (normally the trunk; see - the -b option of rcs(1))." - - RCS_findlock_or_tip finds the unique revision locked by the caller - and returns its delta node. If the caller has not locked any - revisions (and is permitted to commit to an unlocked delta, as - described above), return the tip of the default branch. */ - -static RCSVers * -RCS_findlock_or_tip (rcs) - RCSNode *rcs; -{ - char *user = getcaller(); - Node *lock, *p; - List *locklist; - char *defaultrev = NULL; - - /* Find unique delta locked by caller. This code is very similar - to the code in RCS_unlock -- perhaps it could be abstracted - into a RCS_findlock function. */ - locklist = RCS_getlocks (rcs); - lock = NULL; - for (p = locklist->list->next; p != locklist->list; p = p->next) - { - if (STREQ (p->data, user)) - { - if (lock != NULL) - { - error (0, 0, "\ -%s: multiple revisions locked by %s; please specify one", rcs->path, user); - return NULL; - } - lock = p; - } - } - - if (lock != NULL) - { - /* Found an old lock, but check that the revision still exists. */ - p = findnode (rcs->versions, lock->key); - if (p == NULL) - { - error (0, 0, "%s: can't unlock nonexistent revision %s", - rcs->path, - lock->key); - return NULL; - } - return p->data; - } - - /* No existing lock. The RCS rule is that this is an error unless - locking is nonstrict AND the file is owned by the current - user. Trying to determine the latter is a portability nightmare - in the face of NT, VMS, AFS, and other systems with non-unix-like - ideas of users and owners. In the case of CVS, we should never get - here (as long as the traditional behavior of making sure to call - RCS_lock persists). Anyway, we skip the RCS error checks - and just return the default branch or head. The reasoning is that - those error checks are to make users lock before a checkin, and we do - that in other ways if at all anyway (e.g. rcslock.pl). */ - - defaultrev = RCS_getbranch (rcs, rcs->branch, 0); - p = findnode (rcs->versions, defaultrev); - if (defaultrev != NULL) - free (defaultrev); - if (!p) - { - error (0, 0, "RCS file `%s' does not contain its default revision.", - rcs->path); - return NULL; - } - - return p->data; -} - -/* Revision number string, R, must contain a `.'. - Return a newly-malloc'd copy of the prefix of R up - to but not including the final `.'. */ - -static char * -truncate_revnum (r) - const char *r; -{ - size_t len; - char *new_r; - char *dot = strrchr (r, '.'); - - assert (dot); - len = dot - r; - new_r = xmalloc (len + 1); - memcpy (new_r, r, len); - *(new_r + len) = '\0'; - return new_r; -} - -/* Revision number string, R, must contain a `.'. - R must be writable. Replace the rightmost `.' in R with - the NUL byte and return a pointer to that NUL byte. */ - -static char * -truncate_revnum_in_place (r) - char *r; -{ - char *dot = strrchr (r, '.'); - assert (dot); - *dot = '\0'; - return dot; -} - -/* Revision number strings, R and S, must each contain a `.'. - R and S must be writable and must have the same number of dots. - Truncate R and S for the comparison, then restored them to their - original state. - Return the result (see compare_revnums) of comparing R and S - ignoring differences in any component after the rightmost `.'. */ - -static int -compare_truncated_revnums (r, s) - char *r; - char *s; -{ - char *r_dot = truncate_revnum_in_place (r); - char *s_dot = truncate_revnum_in_place (s); - int cmp; - - assert (numdots (r) == numdots (s)); - - cmp = compare_revnums (r, s); - - *r_dot = '.'; - *s_dot = '.'; - - return cmp; -} - -/* Return a malloc'd copy of the string representing the highest branch - number on BRANCHNODE. If there are no branches on BRANCHNODE, return NULL. - FIXME: isn't the max rev always the last one? - If so, we don't even need a loop. */ - -static char *max_rev PROTO ((const RCSVers *)); - -static char * -max_rev (branchnode) - const RCSVers *branchnode; -{ - Node *head; - Node *bp; - char *max; - - if (branchnode->branches == NULL) - { - return NULL; - } - - max = NULL; - head = branchnode->branches->list; - for (bp = head->next; bp != head; bp = bp->next) - { - if (max == NULL || compare_truncated_revnums (max, bp->key) < 0) - { - max = bp->key; - } - } - assert (max); - - return truncate_revnum (max); -} - -/* Create BRANCH in RCS's delta tree. BRANCH may be either a branch - number or a revision number. In the former case, create the branch - with the specified number; in the latter case, create a new branch - rooted at node BRANCH with a higher branch number than any others. - Return the number of the tip node on the new branch. */ - -static char * -RCS_addbranch (rcs, branch) - RCSNode *rcs; - const char *branch; -{ - char *branchpoint, *newrevnum; - Node *nodep, *bp; - Node *marker; - RCSVers *branchnode; - - assert (branch); - - /* Append to end by default. */ - marker = NULL; - - branchpoint = xstrdup (branch); - if ((numdots (branchpoint) & 1) == 0) - { - truncate_revnum_in_place (branchpoint); - } - - /* Find the branch rooted at BRANCHPOINT. */ - nodep = findnode (rcs->versions, branchpoint); - if (nodep == NULL) - { - error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint); - free (branchpoint); - return NULL; - } - free (branchpoint); - branchnode = nodep->data; - - /* If BRANCH was a full branch number, make sure it is higher than MAX. */ - if ((numdots (branch) & 1) == 1) - { - if (branchnode->branches == NULL) - { - /* We have to create the first branch on this node, which means - appending ".2" to the revision number. */ - newrevnum = (char *) xmalloc (strlen (branch) + 3); - strcpy (newrevnum, branch); - strcat (newrevnum, ".2"); - } - else - { - char *max = max_rev (branchnode); - assert (max); - newrevnum = increment_revnum (max); - free (max); - } - } - else - { - newrevnum = xstrdup (branch); - - if (branchnode->branches != NULL) - { - Node *head; - Node *bp; - - /* Find the position of this new branch in the sorted list - of branches. */ - head = branchnode->branches->list; - for (bp = head->next; bp != head; bp = bp->next) - { - char *dot; - int found_pos; - - /* The existing list must be sorted on increasing revnum. */ - assert (bp->next == head - || compare_truncated_revnums (bp->key, - bp->next->key) < 0); - dot = truncate_revnum_in_place (bp->key); - found_pos = (compare_revnums (branch, bp->key) < 0); - *dot = '.'; - - if (found_pos) - { - break; - } - } - marker = bp; - } - } - - newrevnum = (char *) xrealloc (newrevnum, strlen (newrevnum) + 3); - strcat (newrevnum, ".1"); - - /* Add this new revision number to BRANCHPOINT's branches list. */ - if (branchnode->branches == NULL) - branchnode->branches = getlist(); - bp = getnode(); - bp->key = xstrdup (newrevnum); - - /* Append to the end of the list by default, that is, just before - the header node, `list'. */ - if (marker == NULL) - marker = branchnode->branches->list; - - { - int fail; - fail = insert_before (branchnode->branches, marker, bp); - assert (!fail); - } - - return newrevnum; -} - -/* Check in to RCSFILE with revision REV (which must be greater than - the largest revision) and message MESSAGE (which is checked for - legality). If FLAGS & RCS_FLAGS_DEAD, check in a dead revision. - If FLAGS & RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS & - RCS_FLAGS_MODTIME, use the working file's modification time for the - checkin time. WORKFILE is the working file to check in from, or - NULL to use the usual RCS rules for deriving it from the RCSFILE. - If FLAGS & RCS_FLAGS_KEEPFILE, don't unlink the working file; - unlinking the working file is standard RCS behavior, but is rarely - appropriate for CVS. - - This function should almost exactly mimic the behavior of `rcs ci'. The - principal point of difference is the support here for preserving file - ownership and permissions in the delta nodes. This is not a clean - solution -- precisely because it diverges from RCS's behavior -- but - it doesn't seem feasible to do this anywhere else in the code. [-twp] - - Return value is -1 for error (and errno is set to indicate the - error), positive for error (and an error message has been printed), - or zero for success. */ - -int -RCS_checkin (rcs, workfile_in, message, rev, citime, flags) - RCSNode *rcs; - const char *workfile_in; - const char *message; - const char *rev; - time_t citime; - int flags; -{ - RCSVers *delta, *commitpt; - Deltatext *dtext; - Node *nodep; - char *tmpfile, *changefile; - int dargc = 0; - size_t darg_allocated = 0; - char **dargv = NULL; - size_t bufsize; - int status, checkin_quiet; - struct tm *ftm; - time_t modtime; - int adding_branch = 0; - char *workfile = xstrdup (workfile_in); -#ifdef PRESERVE_PERMISSIONS_SUPPORT - struct stat sb; -#endif - - commitpt = NULL; - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - /* Get basename of working file. Is there a library function to - do this? I couldn't find one. -twp */ - if (workfile == NULL) - { - char *p; - int extlen = strlen (RCSEXT); - assert (rcs->path); - workfile = xstrdup (last_component (rcs->path)); - p = workfile + (strlen (workfile) - extlen); - assert (strncmp (p, RCSEXT, extlen) == 0); - *p = '\0'; - } - - /* If the filename is a symbolic link, follow it and replace it - with the destination of the link. We need to do this before - calling rcs_internal_lockfile, or else we won't put the lock in - the right place. */ - resolve_symlink (&(rcs->path)); - - checkin_quiet = flags & RCS_FLAGS_QUIET; - if (!checkin_quiet) - { - cvs_output (rcs->path, 0); - cvs_output (" <-- ", 7); - cvs_output (workfile, 0); - cvs_output ("\n", 1); - } - - /* Create new delta node. */ - delta = (RCSVers *) xmalloc (sizeof (RCSVers)); - memset (delta, 0, sizeof (RCSVers)); - delta->author = xstrdup (getcaller ()); - if (flags & RCS_FLAGS_MODTIME) - { - struct stat ws; - if (stat (workfile, &ws) < 0) - { - error (1, errno, "cannot stat %s", workfile); - } - modtime = ws.st_mtime; - } - else if (flags & RCS_FLAGS_USETIME) - modtime = citime; - else - (void) time (&modtime); - ftm = gmtime (&modtime); - delta->date = (char *) xmalloc (MAXDATELEN); - (void) sprintf (delta->date, DATEFORM, - ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), - ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, - ftm->tm_min, ftm->tm_sec); - if (flags & RCS_FLAGS_DEAD) - { - delta->state = xstrdup (RCSDEAD); - delta->dead = 1; - } - else - delta->state = xstrdup ("Exp"); - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - /* If permissions should be preserved on this project, then - save the permission info. */ - if (preserve_perms) - { - Node *np; - char buf[64]; /* static buffer should be safe: see usage. -twp */ - - delta->other_delta = getlist(); - - if (CVS_LSTAT (workfile, &sb) < 0) - error (1, errno, "cannot lstat %s", workfile); - - if (S_ISLNK (sb.st_mode)) - { - np = getnode(); - np->type = RCSFIELD; - np->key = xstrdup ("symlink"); - np->data = xreadlink (workfile); - addnode (delta->other_delta, np); - } - else - { - (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); - - /* Save device number. */ - switch (sb.st_mode & S_IFMT) - { - case S_IFREG: break; - case S_IFCHR: - case S_IFBLK: -# ifdef HAVE_STRUCT_STAT_ST_RDEV - np = getnode(); - np->type = RCSFIELD; - np->key = xstrdup ("special"); - sprintf (buf, "%s %lu", - ((sb.st_mode & S_IFMT) == S_IFCHR - ? "character" : "block"), - (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: - error (0, 0, "special file %s has unknown type", workfile); - } - - /* Save hardlinks. */ - delta->hardlinks = list_linked_files_on_disk (workfile); - } - } -#endif - - /* Create a new deltatext node. */ - dtext = (Deltatext *) xmalloc (sizeof (Deltatext)); - memset (dtext, 0, sizeof (Deltatext)); - - dtext->log = make_message_rcslegal (message); - - /* If the delta tree is empty, then there's nothing to link the - new delta into. So make a new delta tree, snarf the working - file contents, and just write the new RCS file. */ - if (rcs->head == NULL) - { - char *newrev; - FILE *fout; - - /* Figure out what the first revision number should be. */ - if (rev == NULL || *rev == '\0') - newrev = xstrdup ("1.1"); - else if (numdots (rev) == 0) - { - newrev = (char *) xmalloc (strlen (rev) + 3); - strcpy (newrev, rev); - strcat (newrev, ".1"); - } - else - newrev = xstrdup (rev); - - /* Don't need to xstrdup NEWREV because it's already dynamic, and - not used for anything else. (Don't need to free it, either.) */ - rcs->head = newrev; - delta->version = xstrdup (newrev); - nodep = getnode(); - nodep->type = RCSVERS; - nodep->delproc = rcsvers_delproc; - nodep->data = delta; - nodep->key = delta->version; - (void) addnode (rcs->versions, nodep); - - dtext->version = xstrdup (newrev); - bufsize = 0; -#ifdef PRESERVE_PERMISSIONS_SUPPORT - if (preserve_perms && !S_ISREG (sb.st_mode)) - /* Pretend file is empty. */ - bufsize = 0; - else -#endif - get_file (workfile, workfile, - rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", - &dtext->text, &bufsize, &dtext->len); - - if (!checkin_quiet) - { - cvs_output ("initial revision: ", 0); - cvs_output (rcs->head, 0); - cvs_output ("\n", 1); - } - - /* We are probably about to invalidate any cached file. */ - rcsbuf_cache_close (); - - fout = rcs_internal_lockfile (rcs->path); - RCS_putadmin (rcs, fout); - RCS_putdtree (rcs, rcs->head, fout); - RCS_putdesc (rcs, fout); - rcs->delta_pos = ftell (fout); - if (rcs->delta_pos == -1) - error (1, errno, "cannot ftell for %s", rcs->path); - putdeltatext (fout, dtext); - rcs_internal_unlockfile (fout, rcs->path); - - if ((flags & RCS_FLAGS_KEEPFILE) == 0) - { - if (unlink_file (workfile) < 0) - /* FIXME-update-dir: message does not include update_dir. */ - error (0, errno, "cannot remove %s", workfile); - } - - if (!checkin_quiet) - cvs_output ("done\n", 5); - - status = 0; - goto checkin_done; - } - - /* Derive a new revision number. From the `ci' man page: - - "If rev is a revision number, it must be higher than the - latest one on the branch to which rev belongs, or must - start a new branch. - - If rev is a branch rather than a revision number, the new - revision is appended to that branch. The level number is - obtained by incrementing the tip revision number of that - branch. If rev indicates a non-existing branch, that - branch is created with the initial revision numbered - rev.1." - - RCS_findlock_or_tip handles the case where REV is omitted. - RCS 5.7 also permits REV to be "$" or to begin with a dot, but - we do not address those cases -- every routine that calls - RCS_checkin passes it a numeric revision. */ - - if (rev == NULL || *rev == '\0') - { - /* Figure out where the commit point is by looking for locks. - If the commit point is at the tip of a branch (or is the - head of the delta tree), then increment its revision number - to obtain the new revnum. Otherwise, start a new - branch. */ - commitpt = RCS_findlock_or_tip (rcs); - if (commitpt == NULL) - { - status = 1; - goto checkin_done; - } - else if (commitpt->next == NULL - || STREQ (commitpt->version, rcs->head)) - delta->version = increment_revnum (commitpt->version); - else - delta->version = RCS_addbranch (rcs, commitpt->version); - } - else - { - /* REV is either a revision number or a branch number. Find the - tip of the target branch. */ - char *branch, *tip, *newrev, *p; - int dots, isrevnum; - - assert (isdigit ((unsigned char) *rev)); - - newrev = xstrdup (rev); - dots = numdots (newrev); - isrevnum = dots & 1; - - branch = xstrdup (rev); - if (isrevnum) - { - p = strrchr (branch, '.'); - *p = '\0'; - } - - /* Find the tip of the target branch. If we got a one- or two-digit - revision number, this will be the head of the tree. Exception: - if rev is a single-field revision equal to the branch number of - the trunk (usually "1") then we want to treat it like an ordinary - branch revision. */ - if (dots == 0) - { - tip = xstrdup (rcs->head); - assert (tip != NULL); - if (atoi (tip) != atoi (branch)) - { - newrev = (char *) xrealloc (newrev, strlen (newrev) + 3); - strcat (newrev, ".1"); - dots = isrevnum = 1; - } - } - else if (dots == 1) - tip = xstrdup (rcs->head); - else - tip = RCS_getbranch (rcs, branch, 1); - - /* If the branch does not exist, and we were supplied an exact - revision number, signal an error. Otherwise, if we were - given only a branch number, create it and set COMMITPT to - the branch point. */ - if (tip == NULL) - { - if (isrevnum) - { - error (0, 0, "%s: can't find branch point %s", - rcs->path, branch); - free (branch); - free (newrev); - status = 1; - 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'; - tip = xstrdup (branch); - } - else - { - if (isrevnum) - { - /* NEWREV must be higher than TIP. */ - if (compare_revnums (tip, newrev) >= 0) - { - error (0, 0, - "%s: revision %s too low; must be higher than %s", - rcs->path, - newrev, tip); - free (branch); - free (newrev); - free (tip); - status = 1; - goto checkin_done; - } - delta->version = xstrdup (newrev); - } - else - /* Just increment the tip number to get the new revision. */ - delta->version = increment_revnum (tip); - } - - nodep = findnode (rcs->versions, tip); - commitpt = nodep->data; - - free (branch); - free (newrev); - free (tip); - } - - assert (delta->version != NULL); - - /* If COMMITPT is locked by us, break the lock. If it's locked - by someone else, signal an error. */ - nodep = findnode (RCS_getlocks (rcs), commitpt->version); - if (nodep != NULL) - { - if (! STREQ (nodep->data, delta->author)) - { - /* If we are adding a branch, then leave the old lock around. - That is sensible in the sense that when adding a branch, - we don't need to use the lock to tell us where to check - in. It is fishy in the sense that if it is our own lock, - we break it. However, this is the RCS 5.7 behavior (at - the end of addbranch in ci.c in RCS 5.7, it calls - removelock only if it is our own lock, not someone - else's). */ - - if (!adding_branch) - { - error (0, 0, "%s: revision %s locked by %s", - rcs->path, - nodep->key, (char *)nodep->data); - status = 1; - goto checkin_done; - } - } - else - delnode (nodep); - } - - dtext->version = xstrdup (delta->version); - - /* Obtain the change text for the new delta. If DELTA is to be the - new head of the tree, then its change text should be the contents - of the working file, and LEAFNODE's change text should be a diff. - Else, DELTA's change text should be a diff between LEAFNODE and - the working file. */ - - tmpfile = cvs_temp_name(); - status = RCS_checkout (rcs, NULL, commitpt->version, NULL, - ((rcs->expand != NULL - && STREQ (rcs->expand, "b")) - ? "-kb" - : "-ko"), - tmpfile, - (RCSCHECKOUTPROC)0, NULL); - if (status != 0) - error (1, 0, - "could not check out revision %s of `%s'", - commitpt->version, rcs->path); - - bufsize = 0; - changefile = cvs_temp_name(); - - /* Diff options should include --binary if the RCS file has -kb set - in its `expand' field. */ - run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a"); - run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n"); - if (rcs->expand && STREQ (rcs->expand, "b")) - run_add_arg_p (&dargc, &darg_allocated, &dargv, "--binary"); - - if (STREQ (commitpt->version, rcs->head) && - numdots (delta->version) == 1) - { - /* If this revision is being inserted on the trunk, the change text - for the new delta should be the contents of the working file ... */ - bufsize = 0; -#ifdef PRESERVE_PERMISSIONS_SUPPORT - if (preserve_perms && !S_ISREG (sb.st_mode)) - /* Pretend file is empty. */ - ; - else -#endif - get_file (workfile, workfile, - rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", - &dtext->text, &bufsize, &dtext->len); - - /* ... and the change text for the old delta should be a diff. */ - commitpt->text = (Deltatext *) xmalloc (sizeof (Deltatext)); - memset (commitpt->text, 0, sizeof (Deltatext)); - - bufsize = 0; - switch (diff_exec (workfile, tmpfile, NULL, NULL, - dargc, dargv, changefile)) - { - case 0: - case 1: - break; - case -1: - /* FIXME-update-dir: message does not include update_dir. */ - error (1, errno, "error diffing %s", workfile); - break; - default: - /* FIXME-update-dir: message does not include update_dir. */ - error (1, 0, "error diffing %s", workfile); - break; - } - - /* OK, the text file case here is really dumb. Logically - speaking we want diff to read the files in text mode, - convert them to the canonical form found in RCS files - (which, we hope at least, is independent of OS--always - bare linefeeds), and then work with change texts in that - format. However, diff_exec both generates change - texts and produces output for user purposes (e.g. patch.c), - and there is no way to distinguish between the two cases. - So we actually implement the text file case by writing the - change text as a text file, then reading it as a text file. - This should cause no harm, but doesn't strike me as - immensely clean. */ - get_file (changefile, changefile, - rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", - &commitpt->text->text, &bufsize, &commitpt->text->len); - - /* If COMMITPT->TEXT->TEXT is NULL, it means that CHANGEFILE - was empty and that there are no differences between revisions. - In that event, we want to force RCS_rewrite to write an empty - string for COMMITPT's change text. Leaving the change text - field set NULL won't work, since that means "preserve the original - change text for this delta." */ - if (commitpt->text->text == NULL) - { - commitpt->text->text = xstrdup (""); - commitpt->text->len = 0; - } - } - else - { - /* This file is not being inserted at the head, but on a side - branch somewhere. Make a diff from the previous revision - to the working file. */ - switch (diff_exec (tmpfile, workfile, NULL, NULL, - dargc, dargv, changefile)) - { - case 0: - case 1: - break; - case -1: - /* FIXME-update-dir: message does not include update_dir. */ - error (1, errno, "error diffing %s", workfile); - break; - default: - /* FIXME-update-dir: message does not include update_dir. */ - error (1, 0, "error diffing %s", workfile); - break; - } - /* See the comment above, at the other get_file invocation, - regarding binary vs. text. */ - get_file (changefile, changefile, - rcs->expand != NULL && STREQ (rcs->expand, "b") ? "rb" : "r", - &dtext->text, &bufsize, - &dtext->len); - if (dtext->text == NULL) - { - dtext->text = xstrdup (""); - dtext->len = 0; - } - } - - run_arg_free_p (dargc, dargv); - free (dargv); - - /* Update DELTA linkage. It is important not to do this before - the very end of RCS_checkin; if an error arises that forces - us to abort checking in, we must not have malformed deltas - partially linked into the tree. - - If DELTA and COMMITPT are on different branches, do nothing -- - DELTA is linked to the tree through COMMITPT->BRANCHES, and we - don't want to change `next' pointers. - - Otherwise, if the nodes are both on the trunk, link DELTA to - COMMITPT; otherwise, link COMMITPT to DELTA. */ - - if (numdots (commitpt->version) == numdots (delta->version)) - { - if (STREQ (commitpt->version, rcs->head)) - { - delta->next = rcs->head; - rcs->head = xstrdup (delta->version); - } - else - commitpt->next = xstrdup (delta->version); - } - - /* Add DELTA to RCS->VERSIONS. */ - if (rcs->versions == NULL) - rcs->versions = getlist(); - nodep = getnode(); - nodep->type = RCSVERS; - nodep->delproc = rcsvers_delproc; - nodep->data = delta; - nodep->key = delta->version; - (void) addnode (rcs->versions, nodep); - - /* Write the new RCS file, inserting the new delta at COMMITPT. */ - if (!checkin_quiet) - { - cvs_output ("new revision: ", 14); - cvs_output (delta->version, 0); - cvs_output ("; previous revision: ", 21); - cvs_output (commitpt->version, 0); - cvs_output ("\n", 1); - } - - RCS_rewrite (rcs, dtext, commitpt->version); - - if ((flags & RCS_FLAGS_KEEPFILE) == 0) - { - if (unlink_file (workfile) < 0) - /* FIXME-update-dir: message does not include update_dir. */ - error (1, errno, "cannot remove %s", workfile); - } - 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); - - checkin_done: - free (workfile); - - if (commitpt != NULL && commitpt->text != NULL) - { - freedeltatext (commitpt->text); - commitpt->text = NULL; - } - - freedeltatext (dtext); - if (status != 0) - { - /* If delta has not been added to a List, then freeing the Node key - * won't free delta->version. - */ - if (delta->version) free (delta->version); - free_rcsvers_contents (delta); - } - - return status; -} - - - -/* This structure is passed between RCS_cmp_file and cmp_file_buffer. */ -struct cmp_file_data -{ - const char *filename; - FILE *fp; - int different; -}; - -/* Compare the contents of revision REV1 of RCS file RCS with the - contents of REV2 if given, otherwise, compare with the contents of - the file FILENAME. OPTIONS is a string for the keyword - expansion options. Return 0 if the contents of the revision are - the same as the contents of the file, 1 if they are different. */ -int -RCS_cmp_file (rcs, rev1, rev1_cache, rev2, options, filename) - RCSNode *rcs; - const char *rev1; - char **rev1_cache; - const char *rev2; - const char *options; - const char *filename; -{ - int binary; - - if (options != NULL && options[0] != '\0') - binary = STREQ (options, "-kb"); - else - { - char *expand; - - expand = RCS_getexpand (rcs); - if (expand != NULL && STREQ (expand, "b")) - binary = 1; - else - binary = 0; - } - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - /* If CVS is to deal properly with special files (when - PreservePermissions is on), the best way is to check out the - revision to a temporary file and call `xcmp' on the two disk - files. xcmp needs to handle non-regular files properly anyway, - so calling it simplifies RCS_cmp_file. We *could* just yank - the delta node out of the version tree and look for device - numbers, but writing to disk and calling xcmp is a better - abstraction (therefore probably more robust). -twp */ - - if (preserve_perms) - { - char *tmp; - int retcode; - - tmp = cvs_temp_name(); - retcode = RCS_checkout(rcs, NULL, rev, NULL, options, tmp, NULL, NULL); - if (retcode != 0) - return 1; - - retcode = xcmp (tmp, filename); - if (CVS_UNLINK (tmp) < 0) - error (0, errno, "cannot remove %s", tmp); - free (tmp); - return retcode; - } - else -#endif - { - FILE *fp; - struct cmp_file_data data; - const char *use_file1; - char *tmpfile = NULL; - - if (rev2 != NULL) - { - /* Open & cache rev1 */ - tmpfile = cvs_temp_name(); - if (RCS_checkout (rcs, NULL, rev1, NULL, options, tmpfile, - (RCSCHECKOUTPROC)0, NULL)) - error (1, errno, - "cannot check out revision %s of %s", - rev1, rcs->path); - use_file1 = tmpfile; - if (rev1_cache != NULL) - *rev1_cache = tmpfile; - } - else - use_file1 = filename; - - fp = CVS_FOPEN (use_file1, binary ? FOPEN_BINARY_READ : "r"); - if (fp == NULL) - /* FIXME-update-dir: should include update_dir in message. */ - error (1, errno, "cannot open file %s for comparing", use_file1); - - data.filename = use_file1; - data.fp = fp; - data.different = 0; - - if (RCS_checkout (rcs, (char *)NULL, rev2 ? rev2 : rev1, - (char *)NULL, options, RUN_TTY, cmp_file_buffer, - (void *)&data )) - error (1, errno, - "cannot check out revision %s of %s", - rev2 ? rev2 : rev1, rcs->path); - - /* If we have not yet found a difference, make sure that we are at - the end of the file. */ - if (!data.different) - { - if (getc (fp) != EOF) - data.different = 1; - } - - fclose (fp); - if (rev1_cache == NULL && tmpfile) - { - if (CVS_UNLINK (tmpfile ) < 0) - error (0, errno, "cannot remove %s", tmpfile); - free (tmpfile); - } - - return data.different; - } -} - - - -/* This is a subroutine of RCS_cmp_file. It is passed to - RCS_checkout. */ -#define CMP_BUF_SIZE (8 * 1024) - -static void -cmp_file_buffer (callerdat, buffer, len) - void *callerdat; - const char *buffer; - size_t len; -{ - struct cmp_file_data *data = (struct cmp_file_data *)callerdat; - char *filebuf; - - /* If we've already found a difference, we don't need to check - further. */ - if (data->different) - return; - - filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len); - - while (len > 0) - { - size_t checklen; - - checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len; - if (fread (filebuf, 1, checklen, data->fp) != checklen) - { - if (ferror (data->fp)) - error (1, errno, "cannot read file %s for comparing", - data->filename); - data->different = 1; - free (filebuf); - return; - } - - if (memcmp (filebuf, buffer, checklen) != 0) - { - data->different = 1; - free (filebuf); - return; - } - - buffer += checklen; - len -= checklen; - } - - free (filebuf); -} - - - -/* For RCS file RCS, make symbolic tag TAG point to revision REV. - This validates that TAG is OK for a user to use. Return value is - -1 for error (and errno is set to indicate the error), positive for - error (and an error message has been printed), or zero for success. */ - -int -RCS_settag (rcs, tag, rev) - RCSNode *rcs; - const char *tag; - const char *rev; -{ - List *symbols; - Node *node; - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - /* FIXME: This check should be moved to RCS_check_tag. There is no - reason for it to be here. */ - if (STREQ (tag, TAG_BASE) - || STREQ (tag, TAG_HEAD)) - { - /* Print the name of the tag might be considered redundant - with the caller, which also prints it. Perhaps this helps - clarify why the tag name is considered reserved, I don't - know. */ - error (0, 0, "Attempt to add reserved tag name %s", tag); - return 1; - } - - /* A revision number of NULL means use the head or default branch. - If rev is not NULL, it may be a symbolic tag or branch number; - expand it to the correct numeric revision or branch head. */ - if (rev == NULL) - rev = rcs->branch ? rcs->branch : rcs->head; - - /* At this point rcs->symbol_data may not have been parsed. - Calling RCS_symbols will force it to be parsed into a list - which we can easily manipulate. */ - symbols = RCS_symbols (rcs); - if (symbols == NULL) - { - symbols = getlist (); - rcs->symbols = symbols; - } - node = findnode (symbols, tag); - if (node != NULL) - { - free (node->data); - node->data = xstrdup (rev); - } - else - { - node = getnode (); - node->key = xstrdup (tag); - node->data = xstrdup (rev); - (void) addnode_at_front (symbols, node); - } - - return 0; -} - -/* Delete the symbolic tag TAG from the RCS file RCS. Return 0 if - the tag was found (and removed), or 1 if it was not present. (In - either case, the tag will no longer be in RCS->SYMBOLS.) */ - -int -RCS_deltag (rcs, tag) - RCSNode *rcs; - const char *tag; -{ - List *symbols; - Node *node; - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - symbols = RCS_symbols (rcs); - if (symbols == NULL) - return 1; - - node = findnode (symbols, tag); - if (node == NULL) - return 1; - - delnode (node); - - return 0; -} - -/* Set the default branch of RCS to REV. */ - -int -RCS_setbranch (rcs, rev) - RCSNode *rcs; - const char *rev; -{ - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - if (rev && ! *rev) - rev = NULL; - - if (rev == NULL && rcs->branch == NULL) - return 0; - if (rev != NULL && rcs->branch != NULL && STREQ (rev, rcs->branch)) - return 0; - - if (rcs->branch != NULL) - free (rcs->branch); - rcs->branch = xstrdup (rev); - - return 0; -} - -/* Lock revision REV. LOCK_QUIET is 1 to suppress output. FIXME: - Most of the callers only call us because RCS_checkin still tends to - like a lock (a relic of old behavior inherited from the RCS ci - program). If we clean this up, only "cvs admin -l" will still need - to call RCS_lock. */ - -/* FIXME-twp: if a lock owned by someone else is broken, should this - send mail to the lock owner? Prompt user? It seems like such an - obscure situation for CVS as almost not worth worrying much - about. */ - -int -RCS_lock (rcs, rev, lock_quiet) - RCSNode *rcs; - const char *rev; - int lock_quiet; -{ - List *locks; - Node *p; - char *user; - char *xrev = NULL; - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - locks = RCS_getlocks (rcs); - if (locks == NULL) - locks = rcs->locks = getlist(); - user = getcaller(); - - /* A revision number of NULL means lock the head or default branch. */ - if (rev == NULL) - xrev = RCS_head (rcs); - else - xrev = RCS_gettag (rcs, rev, 1, (int *) NULL); - - /* Make sure that the desired revision exists. Technically, - we can update the locks list without even checking this, - but RCS 5.7 did this. And it can't hurt. */ - if (xrev == NULL || findnode (rcs->versions, xrev) == NULL) - { - if (!lock_quiet) - error (0, 0, "%s: revision %s absent", rcs->path, rev); - free (xrev); - return 1; - } - - /* Is this rev already locked? */ - p = findnode (locks, xrev); - if (p != NULL) - { - if (STREQ (p->data, user)) - { - /* We already own the lock on this revision, so do nothing. */ - free (xrev); - return 0; - } - -#if 0 - /* Well, first of all, "rev" below should be "xrev" to avoid - core dumps. But more importantly, should we really be - breaking the lock unconditionally? What CVS 1.9 does (via - RCS) is to prompt "Revision 1.1 is already locked by fred. - Do you want to break the lock? [ny](n): ". Well, we don't - want to interact with the user (certainly not at the - server/protocol level, and probably not in the command-line - client), but isn't it more sensible to give an error and - let the user run "cvs admin -u" if they want to break the - lock? */ - - /* Break the lock. */ - if (!lock_quiet) - { - cvs_output (rev, 0); - cvs_output (" unlocked\n", 0); - } - delnode (p); -#else - error (1, 0, "Revision %s is already locked by %s", xrev, (char *)p->data); -#endif - } - - /* Create a new lock. */ - p = getnode(); - p->key = xrev; /* already xstrdupped */ - p->data = xstrdup (getcaller()); - (void) addnode_at_front (locks, p); - - if (!lock_quiet) - { - cvs_output (xrev, 0); - cvs_output (" locked\n", 0); - } - - return 0; -} - -/* Unlock revision REV. UNLOCK_QUIET is 1 to suppress output. FIXME: - Like RCS_lock, this can become a no-op if we do the checkin - ourselves. - - If REV is not null and is locked by someone else, break their - lock and notify them. It is an open issue whether RCS_unlock - queries the user about whether or not to break the lock. */ - -int -RCS_unlock (rcs, rev, unlock_quiet) - RCSNode *rcs; - char *rev; - int unlock_quiet; -{ - Node *lock; - List *locks; - char *user; - char *xrev = NULL; - - user = getcaller(); - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - /* If rev is NULL, unlock the revision held by the caller; if more - than one, make the user specify the revision explicitly. This - differs from RCS which unlocks the latest revision (first in - rcs->locks) held by the caller. */ - if (rev == NULL) - { - Node *p; - - /* No-ops: attempts to unlock an empty tree or an unlocked file. */ - if (rcs->head == NULL) - { - if (!unlock_quiet) - cvs_outerr ("can't unlock an empty tree\n", 0); - return 0; - } - - locks = RCS_getlocks (rcs); - if (locks == NULL) - { - if (!unlock_quiet) - cvs_outerr ("No locks are set.\n", 0); - return 0; - } - - lock = NULL; - for (p = locks->list->next; p != locks->list; p = p->next) - { - if (STREQ (p->data, user)) - { - if (lock != NULL) - { - if (!unlock_quiet) - error (0, 0, "\ -%s: multiple revisions locked by %s; please specify one", rcs->path, user); - return 1; - } - lock = p; - } - } - if (lock == NULL) - { - if (!unlock_quiet) - error (0, 0, "No locks are set for %s.\n", user); - return 0; /* no lock found, ergo nothing to do */ - } - xrev = xstrdup (lock->key); - } - else - { - xrev = RCS_gettag (rcs, rev, 1, (int *) NULL); - if (xrev == NULL) - { - error (0, 0, "%s: revision %s absent", rcs->path, rev); - return 1; - } - } - - lock = findnode (RCS_getlocks (rcs), xrev); - if (lock == NULL) - { - /* This revision isn't locked. */ - free (xrev); - return 0; - } - - if (! STREQ (lock->data, user)) - { - /* If the revision is locked by someone else, notify - them. Note that this shouldn't ever happen if RCS_unlock - is called with a NULL revision, since that means "whatever - revision is currently locked by the caller." */ - char *repos, *workfile; - if (!unlock_quiet) - error (0, 0, "\ -%s: revision %s locked by %s; breaking lock", rcs->path, xrev, (char *)lock->data); - repos = xstrdup (rcs->path); - workfile = strrchr (repos, '/'); - *workfile++ = '\0'; - notify_do ('C', workfile, user, NULL, NULL, repos); - free (repos); - } - - delnode (lock); - if (!unlock_quiet) - { - cvs_output (xrev, 0); - cvs_output (" unlocked\n", 0); - } - - free (xrev); - return 0; -} - -/* Add USER to the access list of RCS. Do nothing if already present. - FIXME-twp: check syntax of USER to make sure it's a valid id. */ - -void -RCS_addaccess (rcs, user) - RCSNode *rcs; - char *user; -{ - char *access, *a; - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - if (rcs->access == NULL) - rcs->access = xstrdup (user); - else - { - access = xstrdup (rcs->access); - for (a = strtok (access, " "); a != NULL; a = strtok (NULL, " ")) - { - if (STREQ (a, user)) - { - free (access); - return; - } - } - free (access); - rcs->access = (char *) xrealloc - (rcs->access, strlen (rcs->access) + strlen (user) + 2); - strcat (rcs->access, " "); - strcat (rcs->access, user); - } -} - -/* Remove USER from the access list of RCS. */ - -void -RCS_delaccess (rcs, user) - RCSNode *rcs; - char *user; -{ - char *p, *s; - int ulen; - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - 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 (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' ')) - break; - p = strchr (p, ' '); - if (p != NULL) - ++p; - } - - if (p == NULL) - return; - - s = p + ulen; - while (*s != '\0') - *p++ = *s++; - *p = '\0'; -} - -char * -RCS_getaccess (rcs) - RCSNode *rcs; -{ - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - return rcs->access; -} - -static int findtag PROTO ((Node *, void *)); - -/* Return a nonzero value if the revision specified by ARG is found. */ - -static int -findtag (node, arg) - Node *node; - void *arg; -{ - char *rev = (char *)arg; - - if (STREQ (node->data, rev)) - return 1; - else - return 0; -} - -static int findmagictag PROTO ((Node *, void *)); - -/* Return a nonzero value if a magic tag rooted at ARG is found. */ - -static int -findmagictag (node, arg) - Node *node; - void *arg; -{ - char *rev = (char *)arg; - size_t len = strlen (rev); - - if (strncmp (node->data, rev, len) == 0 && - strncmp ((char *)node->data + len, ".0.", 3) == 0) - return 1; - else - return 0; -} - -/* Delete revisions between REV1 and REV2. The changes between the two - revisions must be collapsed, and the result stored in the revision - immediately preceding the lower one. Return 0 for successful completion, - 1 otherwise. - - Solution: check out the revision preceding REV1 and the revision - following REV2. Use call_diff to find aggregate diffs between - these two revisions, and replace the delta text for the latter one - with the new aggregate diff. Alternatively, we could write a - function that takes two change texts and combines them to produce a - new change text, without checking out any revs or calling diff. It - would be hairy, but so, so cool. - - If INCLUSIVE is set, then TAG1 and TAG2, if non-NULL, tell us to - delete that revision as well (cvs admin -o tag1:tag2). If clear, - delete up to but not including that revision (cvs admin -o tag1::tag2). - This does not affect TAG1 or TAG2 being NULL; the meaning of the start - point in ::tag2 and :tag2 is the same and likewise for end points. */ - -int -RCS_delete_revs (rcs, tag1, tag2, inclusive) - RCSNode *rcs; - char *tag1; - char *tag2; - int inclusive; -{ - char *next; - Node *nodep; - RCSVers *revp = NULL; - RCSVers *beforep; - int status, found; - int save_noexec; - - char *branchpoint = NULL; - char *rev1 = NULL; - char *rev2 = NULL; - int rev1_inclusive = inclusive; - int rev2_inclusive = inclusive; - char *before = NULL; - char *after = NULL; - char *beforefile = NULL; - char *afterfile = NULL; - char *outfile = NULL; - - if (tag1 == NULL && tag2 == NULL) - return 0; - - /* Assume error status until everything is finished. */ - status = 1; - - /* Make sure both revisions exist. */ - if (tag1 != NULL) - { - rev1 = RCS_gettag (rcs, tag1, 1, NULL); - if (rev1 == NULL || (nodep = findnode (rcs->versions, rev1)) == NULL) - { - error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag1); - goto delrev_done; - } - } - if (tag2 != NULL) - { - rev2 = RCS_gettag (rcs, tag2, 1, NULL); - if (rev2 == NULL || (nodep = findnode (rcs->versions, rev2)) == NULL) - { - error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, tag2); - goto delrev_done; - } - } - - /* If rev1 is on the trunk and rev2 is NULL, rev2 should be - RCS->HEAD. (*Not* RCS_head(rcs), which may return rcs->branch - instead.) We need to check this special case early, in order - to make sure that rev1 and rev2 get ordered correctly. */ - if (rev2 == NULL && numdots (rev1) == 1) - { - rev2 = xstrdup (rcs->head); - rev2_inclusive = 1; - } - - if (rev2 == NULL) - rev2_inclusive = 1; - - if (rev1 != NULL && rev2 != NULL) - { - /* A range consisting of a branch number means the latest revision - on that branch. */ - if (RCS_isbranch (rcs, rev1) && STREQ (rev1, rev2)) - { - char *tmp = RCS_getbranch (rcs, rev1, 0); - free (rev1); - free (rev2); - rev1 = rev2 = tmp; - } - else - { - /* Make sure REV1 and REV2 are ordered correctly (in the - same order as the next field). For revisions on the - trunk, REV1 should be higher than REV2; for branches, - REV1 should be lower. */ - /* Shouldn't we just be giving an error in the case where - the user specifies the revisions in the wrong order - (that is, always swap on the trunk, never swap on a - branch, in the non-error cases)? It is not at all - clear to me that users who specify -o 1.4:1.2 really - meant to type -o 1.2:1.4, and the out of order usage - has never been documented, either by cvs.texinfo or - rcs(1). */ - char *temp; - int temp_inclusive; - if (numdots (rev1) == 1) - { - if (compare_revnums (rev1, rev2) <= 0) - { - temp = rev2; - rev2 = rev1; - rev1 = temp; - - temp_inclusive = rev2_inclusive; - rev2_inclusive = rev1_inclusive; - rev1_inclusive = temp_inclusive; - } - } - else if (compare_revnums (rev1, rev2) > 0) - { - temp = rev2; - rev2 = rev1; - rev1 = temp; - - temp_inclusive = rev2_inclusive; - rev2_inclusive = rev1_inclusive; - rev1_inclusive = temp_inclusive; - } - } - } - - /* Basically the same thing; make sure that the ordering is what we - need. */ - if (rev1 == NULL) - { - assert (rev2 != NULL); - if (numdots (rev2) == 1) - { - /* Swap rev1 and rev2. */ - int temp_inclusive; - - rev1 = rev2; - rev2 = NULL; - - temp_inclusive = rev2_inclusive; - rev2_inclusive = rev1_inclusive; - rev1_inclusive = temp_inclusive; - } - } - - /* Put the revision number preceding the first one to delete into - BEFORE (where "preceding" means according to the next field). - If the first revision to delete is the first revision on its - branch (e.g. 1.3.2.1), BEFORE should be the node on the trunk - at which the branch is rooted. If the first revision to delete - is the head revision of the trunk, set BEFORE to NULL. - - Note that because BEFORE may not be on the same branch as REV1, - it is not very handy for navigating the revision tree. It's - most useful just for checking out the revision preceding REV1. */ - before = NULL; - branchpoint = RCS_getbranchpoint (rcs, rev1 != NULL ? rev1 : rev2); - if (rev1 == NULL) - { - rev1 = xstrdup (branchpoint); - if (numdots (branchpoint) > 1) - { - char *bp; - bp = strrchr (branchpoint, '.'); - while (*--bp != '.') - ; - *bp = '\0'; - /* Note that this is exclusive, always, because the inclusive - flag doesn't affect the meaning when rev1 == NULL. */ - before = xstrdup (branchpoint); - *bp = '.'; - } - } - else if (! STREQ (rev1, branchpoint)) - { - /* Walk deltas from BRANCHPOINT on, looking for REV1. */ - nodep = findnode (rcs->versions, branchpoint); - revp = nodep->data; - while (revp->next != NULL && ! STREQ (revp->next, rev1)) - { - revp = nodep->data; - nodep = findnode (rcs->versions, revp->next); - } - if (revp->next == NULL) - { - error (0, 0, "%s: Revision %s doesn't exist.", rcs->path, rev1); - goto delrev_done; - } - if (rev1_inclusive) - before = xstrdup (revp->version); - else - { - before = rev1; - nodep = findnode (rcs->versions, before); - rev1 = xstrdup (((RCSVers *)nodep->data)->next); - } - } - else if (!rev1_inclusive) - { - before = rev1; - nodep = findnode (rcs->versions, before); - rev1 = xstrdup (((RCSVers *)nodep->data)->next); - } - else if (numdots (branchpoint) > 1) - { - /* Example: rev1 is "1.3.2.1", branchpoint is "1.3.2.1". - Set before to "1.3". */ - char *bp; - bp = strrchr (branchpoint, '.'); - while (*--bp != '.') - ; - *bp = '\0'; - before = xstrdup (branchpoint); - *bp = '.'; - } - - /* If any revision between REV1 and REV2 is locked or is a branch point, - we can't delete that revision and must abort. */ - after = NULL; - next = rev1; - found = 0; - while (!found && next != NULL) - { - nodep = findnode (rcs->versions, next); - revp = nodep->data; - - if (rev2 != NULL) - found = STREQ (revp->version, rev2); - next = revp->next; - - if ((!found && next != NULL) || rev2_inclusive || rev2 == NULL) - { - if (findnode (RCS_getlocks (rcs), revp->version)) - { - error (0, 0, "%s: can't remove locked revision %s", - rcs->path, - revp->version); - goto delrev_done; - } - if (revp->branches != NULL) - { - error (0, 0, "%s: can't remove branch point %s", - rcs->path, - revp->version); - goto delrev_done; - } - - /* Doing this only for the :: syntax is for compatibility. - See cvs.texinfo for somewhat more discussion. */ - if (!inclusive && - (walklist (RCS_symbols (rcs), findtag, revp->version) || - walklist (RCS_symbols (rcs), findmagictag, revp->version))) - { - /* We don't print which file this happens to on the theory - that the caller will print the name of the file in a - more useful fashion (fullname not rcs->path). */ - error (0, 0, "cannot remove revision %s because it has tags", - revp->version); - goto delrev_done; - } - - /* It's misleading to print the `deleting revision' output - here, since we may not actually delete these revisions. - But that's how RCS does it. Bleah. Someday this should be - moved to the point where the revs are actually marked for - deletion. -twp */ - cvs_output ("deleting revision ", 0); - cvs_output (revp->version, 0); - cvs_output ("\n", 1); - } - } - - if (rev2 == NULL) - ; - else if (found) - { - if (rev2_inclusive) - after = xstrdup (next); - else - after = xstrdup (revp->version); - } - else if (!inclusive) - { - /* In the case of an empty range, for example 1.2::1.2 or - 1.2::1.3, we want to just do nothing. */ - status = 0; - goto delrev_done; - } - else - { - /* This looks fishy in the cases where tag1 == NULL or tag2 == NULL. - Are those cases really impossible? */ - assert (tag1 != NULL); - assert (tag2 != NULL); - - error (0, 0, "%s: invalid revision range %s:%s", rcs->path, - tag1, tag2); - goto delrev_done; - } - - if (after == NULL && before == NULL) - { - /* The user is trying to delete all revisions. While an - RCS file without revisions makes sense to RCS (e.g. the - state after "rcs -i"), CVS has never been able to cope with - it. So at least for now we just make this an error. - - We don't include rcs->path in the message since "cvs admin" - already printed "RCS file:" and the name. */ - error (1, 0, "attempt to delete all revisions"); - } - - /* The conditionals at this point get really hairy. Here is the - general idea: - - IF before != NULL and after == NULL - THEN don't check out any revisions, just delete them - IF before == NULL and after != NULL - THEN only check out after's revision, and use it for the new deltatext - ELSE - check out both revisions and diff -n them. This could use - RCS_exec_rcsdiff with some changes, like being able - to suppress diagnostic messages and to direct output. */ - - if (after != NULL) - { - char *diffbuf; - size_t bufsize, len; - -#if defined (WOE32) && !defined (__CYGWIN32__) - /* FIXME: This is an awful kludge, but at least until I have - time to work on it a little more and test it, I'd rather - give a fatal error than corrupt the file. I think that we - need to use "-kb" and "--binary" and "rb" to get_file - (probably can do it always, not just for binary files, if - we are consistent between the RCS_checkout and the diff). */ - { - char *expand = RCS_getexpand (rcs); - if (expand != NULL && STREQ (expand, "b")) - error (1, 0, - "admin -o not implemented yet for binary on this system"); - } -#endif /* WOE32 */ - - afterfile = cvs_temp_name(); - status = RCS_checkout (rcs, NULL, after, NULL, "-ko", afterfile, - (RCSCHECKOUTPROC)0, NULL); - if (status > 0) - goto delrev_done; - - if (before == NULL) - { - /* We are deleting revisions from the head of the tree, - so must create a new head. */ - diffbuf = NULL; - bufsize = 0; - get_file (afterfile, afterfile, "r", &diffbuf, &bufsize, &len); - - save_noexec = noexec; - noexec = 0; - if (unlink_file (afterfile) < 0) - error (0, errno, "cannot remove %s", afterfile); - noexec = save_noexec; - - free (afterfile); - afterfile = NULL; - - free (rcs->head); - rcs->head = xstrdup (after); - } - else - { - int dargc = 0; - size_t darg_allocated = 0; - char **dargv = NULL; - - beforefile = cvs_temp_name(); - status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile, - (RCSCHECKOUTPROC)0, NULL); - if (status > 0) - goto delrev_done; - - outfile = cvs_temp_name(); - run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a"); - run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n"); - status = diff_exec (beforefile, afterfile, NULL, NULL, - dargc, dargv, outfile); - run_arg_free_p (dargc, dargv); - free (dargv); - - if (status == 2) - { - /* Not sure we need this message; will diff_exec already - have printed an error? */ - error (0, 0, "%s: could not diff", rcs->path); - status = 1; - goto delrev_done; - } - - diffbuf = NULL; - bufsize = 0; - get_file (outfile, outfile, "r", &diffbuf, &bufsize, &len); - } - - /* Save the new change text in after's delta node. */ - nodep = findnode (rcs->versions, after); - revp = nodep->data; - - assert (revp->text == NULL); - - revp->text = (Deltatext *) xmalloc (sizeof (Deltatext)); - memset ((Deltatext *) revp->text, 0, sizeof (Deltatext)); - revp->text->version = xstrdup (revp->version); - revp->text->text = diffbuf; - revp->text->len = len; - - /* If DIFFBUF is NULL, it means that OUTFILE is empty and that - there are no differences between the two revisions. In that - case, we want to force RCS_copydeltas to write an empty string - for the new change text (leaving the text field set NULL - means "preserve the original change text for this delta," so - we don't want that). */ - if (revp->text->text == NULL) - revp->text->text = xstrdup (""); - } - - /* Walk through the revisions (again) to mark each one as - outdated. (FIXME: would it be safe to use the `dead' field for - this? Doubtful.) */ - for (next = rev1; - next != NULL && (after == NULL || ! STREQ (next, after)); - next = revp->next) - { - nodep = findnode (rcs->versions, next); - revp = nodep->data; - revp->outdated = 1; - } - - /* Update delta links. If BEFORE == NULL, we're changing the - head of the tree and don't need to update any `next' links. */ - if (before != NULL) - { - /* If REV1 is the first node on its branch, then BEFORE is its - root node (on the trunk) and we have to update its branches - list. Otherwise, BEFORE is on the same branch as AFTER, and - we can just change BEFORE's `next' field to point to AFTER. - (This should be safe: since findnode manages its lists via - the `hashnext' and `hashprev' fields, rather than `next' and - `prev', mucking with `next' and `prev' should not corrupt the - delta tree's internal structure. Much. -twp) */ - - if (rev1 == NULL) - /* beforep's ->next field already should be equal to after, - which I think is always NULL in this case. */ - ; - else if (STREQ (rev1, branchpoint)) - { - nodep = findnode (rcs->versions, before); - revp = nodep->data; - nodep = revp->branches->list->next; - while (nodep != revp->branches->list && - ! STREQ (nodep->key, rev1)) - nodep = nodep->next; - assert (nodep != revp->branches->list); - if (after == NULL) - delnode (nodep); - else - { - free (nodep->key); - nodep->key = xstrdup (after); - } - } - else - { - nodep = findnode (rcs->versions, before); - beforep = nodep->data; - free (beforep->next); - beforep->next = xstrdup (after); - } - } - - status = 0; - - delrev_done: - if (rev1 != NULL) - free (rev1); - if (rev2 && rev2 != rev1) - free (rev2); - if (branchpoint != NULL) - free (branchpoint); - if (before != NULL) - free (before); - if (after != NULL) - free (after); - - save_noexec = noexec; - noexec = 0; - if (beforefile != NULL) - { - if (unlink_file (beforefile) < 0) - error (0, errno, "cannot remove %s", beforefile); - free (beforefile); - } - if (afterfile != NULL) - { - if (unlink_file (afterfile) < 0) - error (0, errno, "cannot remove %s", afterfile); - free (afterfile); - } - if (outfile != NULL) - { - if (unlink_file (outfile) < 0) - error (0, errno, "cannot remove %s", outfile); - free (outfile); - } - noexec = save_noexec; - - return status; -} - -/* - * TRUE if there exists a symbolic tag "tag" in file. - */ -int -RCS_exist_tag (rcs, tag) - RCSNode *rcs; - char *tag; -{ - - assert (rcs != NULL); - - if (findnode (RCS_symbols (rcs), tag)) - return 1; - return 0; - -} - -/* - * TRUE if RCS revision number "rev" exists. - * This includes magic branch revisions, not found in rcs->versions, - * but only in rcs->symbols, requiring a list walk to find them. - * Take advantage of list walk callback function already used by - * RCS_delete_revs, above. - */ -int -RCS_exist_rev (rcs, rev) - RCSNode *rcs; - char *rev; -{ - - assert (rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); - - if (findnode(rcs->versions, rev) != 0) - return 1; - - if (walklist (RCS_symbols(rcs), findtag, rev) != 0) - return 1; - - return 0; - -} - - -/* RCS_deltas and friends. Processing of the deltas in RCS files. */ - -struct line -{ - /* Text of this line. Part of the same malloc'd block as the struct - line itself (we probably should use the "struct hack" (char text[1]) - and save ourselves sizeof (char *) bytes). Does not include \n; - instead has_newline indicates the presence or absence of \n. */ - char *text; - /* Length of this line, not counting \n if has_newline is true. */ - size_t len; - /* Version in which it was introduced. */ - RCSVers *vers; - /* Nonzero if this line ends with \n. This will always be true - except possibly for the last line. */ - int has_newline; - /* Number of pointers to this struct line. */ - int refcount; -}; - -struct linevector -{ - /* How many lines in use for this linevector? */ - unsigned int nlines; - /* How many lines allocated for this linevector? */ - unsigned int lines_alloced; - /* Pointer to array containing a pointer to each line. */ - struct line **vector; -}; - -static void linevector_init PROTO ((struct linevector *)); - -/* Initialize *VEC to be a linevector with no lines. */ -static void -linevector_init (vec) - struct linevector *vec; -{ - vec->lines_alloced = 0; - vec->nlines = 0; - vec->vector = NULL; -} - -static int linevector_add PROTO ((struct linevector *vec, const char *text, - size_t len, RCSVers *vers, - unsigned int pos)); - -/* Given some text TEXT, add each of its lines to VEC before line POS - (where line 0 is the first line). The last line in TEXT may or may - not be \n terminated. - Set the version for each of the new lines to VERS. This - function returns non-zero for success. It returns zero if the line - number is out of range. - - Each of the lines in TEXT are copied to space which is managed with - the linevector (and freed by linevector_free). So the caller doesn't - need to keep TEXT around after the call to this function. */ -static int -linevector_add (vec, text, len, vers, pos) - struct linevector *vec; - const char *text; - size_t len; - RCSVers *vers; - unsigned int pos; -{ - const char *textend; - unsigned int i; - unsigned int nnew; - const char *p; - const char *nextline_text; - size_t nextline_len; - int nextline_newline; - struct line *q; - - if (len == 0) - return 1; - - textend = text + len; - - /* Count the number of lines we will need to add. */ - nnew = 1; - for (p = text; p < textend; ++p) - if (*p == '\n' && p + 1 < textend) - ++nnew; - - /* Expand VEC->VECTOR if needed. */ - if (vec->nlines + nnew >= vec->lines_alloced) - { - if (vec->lines_alloced == 0) - vec->lines_alloced = 10; - while (vec->nlines + nnew >= vec->lines_alloced) - vec->lines_alloced *= 2; - vec->vector = xrealloc (vec->vector, - vec->lines_alloced * sizeof (*vec->vector)); - } - - /* Make room for the new lines in VEC->VECTOR. */ - for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i) - vec->vector[i] = vec->vector[i - nnew]; - - if (pos > vec->nlines) - return 0; - - /* Actually add the lines, to VEC->VECTOR. */ - i = pos; - nextline_text = text; - nextline_newline = 0; - for (p = text; p < textend; ++p) - if (*p == '\n') - { - nextline_newline = 1; - if (p + 1 == textend) - /* If there are no characters beyond the last newline, we - don't consider it another line. */ - break; - nextline_len = p - nextline_text; - q = (struct line *) xmalloc (sizeof (struct line) + nextline_len); - q->vers = vers; - q->text = (char *)q + sizeof (struct line); - q->len = nextline_len; - q->has_newline = nextline_newline; - q->refcount = 1; - memcpy (q->text, nextline_text, nextline_len); - vec->vector[i++] = q; - - nextline_text = (char *)p + 1; - nextline_newline = 0; - } - nextline_len = p - nextline_text; - q = (struct line *) xmalloc (sizeof (struct line) + nextline_len); - q->vers = vers; - q->text = (char *)q + sizeof (struct line); - q->len = nextline_len; - q->has_newline = nextline_newline; - q->refcount = 1; - memcpy (q->text, nextline_text, nextline_len); - vec->vector[i] = q; - - vec->nlines += nnew; - - return 1; -} - -static void linevector_copy PROTO ((struct linevector *, struct linevector *)); - -/* Copy FROM to TO, copying the vectors but not the lines pointed to. */ -static void -linevector_copy (to, from) - struct linevector *to; - struct linevector *from; -{ - unsigned int ln; - - for (ln = 0; ln < to->nlines; ++ln) - { - if (--to->vector[ln]->refcount == 0) - free (to->vector[ln]); - } - if (from->nlines > to->lines_alloced) - { - if (to->lines_alloced == 0) - to->lines_alloced = 10; - while (from->nlines > to->lines_alloced) - to->lines_alloced *= 2; - to->vector = (struct line **) - xrealloc (to->vector, to->lines_alloced * sizeof (*to->vector)); - } - memcpy (to->vector, from->vector, - from->nlines * sizeof (*to->vector)); - to->nlines = from->nlines; - for (ln = 0; ln < to->nlines; ++ln) - ++to->vector[ln]->refcount; -} - -static void linevector_free PROTO ((struct linevector *)); - -/* Free storage associated with linevector. */ -static void -linevector_free (vec) - struct linevector *vec; -{ - unsigned int ln; - - if (vec->vector != NULL) - { - for (ln = 0; ln < vec->nlines; ++ln) - if (vec->vector[ln] && --vec->vector[ln]->refcount == 0) - free (vec->vector[ln]); - - free (vec->vector); - } -} - -static char *month_printname PROTO ((char *)); - -/* Given a textual string giving the month (1-12), terminated with any - character not recognized by atoi, return the 3 character name to - print it with. I do not think it is a good idea to change these - strings based on the locale; they are standard abbreviations (for - example in rfc822 mail messages) which should be widely understood. - Returns a pointer into static readonly storage. */ -static char * -month_printname (month) - char *month; -{ - static const char *const months[] = - {"Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - int mnum; - - mnum = atoi (month); - if (mnum < 1 || mnum > 12) - return "???"; - return (char *)months[mnum - 1]; -} - -static int -apply_rcs_changes PROTO ((struct linevector *, const char *, size_t, - const char *, RCSVers *, RCSVers *)); - -/* Apply changes to the line vector LINES. DIFFBUF is a buffer of - * length DIFFLEN holding the change text from an RCS file (the output - * of diff -n). NAME is used in error messages. The VERS field of - * any line added is set to ADDVERS. The VERS field of any line - * deleted is set to DELVERS, unless DELVERS is NULL, in which case - * the VERS field of deleted lines is unchanged. - * - * RETURNS - * Non-zero if the change text is applied successfully to ORIG_LINES. - * - * If the change text does not appear to apply to ORIG_LINES (e.g., a - * line number is invalid), this function will return zero and ORIG_LINES - * will remain unmolested. - * - * ERRORS - * If the change text is improperly formatted (e.g., it is not the output - * of diff -n), the function calls error with a status of 1, causing the - * program to exit. - */ -static int -apply_rcs_changes (orig_lines, diffbuf, difflen, name, addvers, delvers) - struct linevector *orig_lines; - const char *diffbuf; - size_t difflen; - const char *name; - RCSVers *addvers; - RCSVers *delvers; -{ - const char *p; - const char *q; - int op; - /* The RCS format throws us for a loop in that the deltafrags (if - we define a deltafrag as an add or a delete) need to be applied - in reverse order. So we stick them into a linked list. */ - struct deltafrag { - enum {FRAG_ADD, FRAG_DELETE} type; - unsigned long pos; - unsigned long nlines; - const char *new_lines; - size_t len; - struct deltafrag *next; - }; - struct deltafrag *dfhead; - struct deltafrag **dftail; - struct deltafrag *df; - unsigned long numlines, lastmodline, offset; - struct linevector lines; - int err; - - dfhead = NULL; - dftail = &dfhead; - numlines = orig_lines->nlines; /* start with init # of lines */ - for (p = diffbuf; p != NULL && p < diffbuf + difflen; ) - { - op = *p++; - if (op != 'a' && op != 'd') - /* Can't just skip over the deltafrag, because the value - of op determines the syntax. */ - error (1, 0, "unrecognized operation '\\x%x' in %s", - op, name); - *dftail = df = xmalloc (sizeof *df); - *(dftail = &df->next) = NULL; - - df->pos = strtoul (p, (char **) &q, 10); - - if (p == q) - error (1, 0, "number expected in %s", name); - p = q; - if (*p++ != ' ') - error (1, 0, "space expected in %s", name); - df->nlines = strtoul (p, (char **) &q, 10); - if (p == q) - error (1, 0, "number expected in %s", name); - p = q; - if (*p++ != '\012') - error (1, 0, "linefeed expected in %s", name); - - if (op == 'a') - { - unsigned int i; - - df->type = FRAG_ADD; - i = df->nlines; - /* The text we want is the number of lines specified, or - until the end of the value, whichever comes first (it - will be the former except in the case where we are - adding a line which does not end in newline). */ - for (q = p; i != 0; ++q) - if (*q == '\n') - --i; - else if (q == diffbuf + difflen) - { - if (i != 1) - error (1, 0, "premature end of change in %s", name); - else - break; - } - - /* Stash away a pointer to the text we are adding. */ - df->new_lines = p; - df->len = q - p; - - p = q; - numlines += df->nlines; - } - else - { - /* Correct for the fact that line numbers in RCS files - start with 1. */ - --df->pos; - - assert (op == 'd'); - df->type = FRAG_DELETE; - numlines -= df->nlines; - } - } - - /* New temp data structure to hold new org before - copy back into original structure. */ - lines.nlines = lines.lines_alloced = numlines; - lines.vector = xmalloc (numlines * sizeof *lines.vector); - - /* We changed the list order to first to last -- so the - list never gets larger than the size numlines. */ - lastmodline = 0; - - /* offset created when adding/removing lines - between new and original structure */ - offset = 0; - err = 0; - for (df = dfhead; df != NULL; ) - { - unsigned int ln; - unsigned long deltaend; - - if (df->pos > orig_lines->nlines) - err = 1; - - /* On error, just free the rest of the list. */ - if (!err) - { - /* Here we need to get to the line where the next insert will - begin, which is DF->pos in ORIG_LINES. We will fill up to - DF->pos - OFFSET in LINES with original items. */ - for (deltaend = df->pos - offset; - lastmodline < deltaend; - lastmodline++) - { - /* we need to copy from the orig structure into new one */ - lines.vector[lastmodline] = - orig_lines->vector[lastmodline + offset]; - lines.vector[lastmodline]->refcount++; - } - - switch (df->type) - { - case FRAG_ADD: - { - const char *textend, *p; - const char *nextline_text; - struct line *q; - int nextline_newline; - size_t nextline_len; - - textend = df->new_lines + df->len; - nextline_newline = 0; - nextline_text = df->new_lines; - for (p = df->new_lines; p < textend; ++p) - { - if (*p == '\n') - { - nextline_newline = 1; - if (p + 1 == textend) - { - /* If there are no characters beyond the - last newline, we don't consider it - another line. */ - break; - } - - nextline_len = p - nextline_text; - q = xmalloc (sizeof *q + nextline_len); - q->vers = addvers; - q->text = (char *)(q + 1); - q->len = nextline_len; - q->has_newline = nextline_newline; - q->refcount = 1; - memcpy (q->text, nextline_text, nextline_len); - lines.vector[lastmodline++] = q; - offset--; - - nextline_text = (char *)p + 1; - nextline_newline = 0; - } - } - nextline_len = p - nextline_text; - q = xmalloc (sizeof *q + nextline_len); - q->vers = addvers; - q->text = (char *)(q + 1); - q->len = nextline_len; - q->has_newline = nextline_newline; - q->refcount = 1; - memcpy (q->text, nextline_text, nextline_len); - lines.vector[lastmodline++] = q; - - /* For each line we add the offset between the #'s - decreases. */ - offset--; - break; - } - - case FRAG_DELETE: - /* we are removing this many lines from the source. */ - offset += df->nlines; - - if (df->pos + df->nlines > orig_lines->nlines) - err = 1; - else if (delvers) - for (ln = df->pos; ln < df->pos + df->nlines; ++ln) - if (orig_lines->vector[ln]->refcount > 1) - /* Annotate needs this but, since the original - * vector is disposed of before returning from - * this function, we only need keep track if - * there are multiple references. - */ - orig_lines->vector[ln]->vers = delvers; - break; - } - } - - df = df->next; - free (dfhead); - dfhead = df; - } - - if (err) - { - /* No reason to try and move a half-mutated and known invalid - * text into the output buffer. - */ - linevector_free (&lines); - } - else - { - /* add the rest of the remaining lines to the data vector */ - for (; lastmodline < numlines; lastmodline++) - { - /* we need to copy from the orig structure into new one */ - lines.vector[lastmodline] = orig_lines->vector[lastmodline - + offset]; - lines.vector[lastmodline]->refcount++; - } - - /* Move the lines vector to the original structure for output, - * first deleting the old. - */ - linevector_free (orig_lines); - orig_lines->vector = lines.vector; - orig_lines->lines_alloced = numlines; - orig_lines->nlines = lines.nlines; - } - - return !err; -} - -/* Apply an RCS change text to a buffer. The function name starts - with rcs rather than RCS because this does not take an RCSNode - argument. NAME is used in error messages. TEXTBUF is the text - buffer to change, and TEXTLEN is the size. DIFFBUF and DIFFLEN are - the change buffer and size. The new buffer is returned in *RETBUF - and *RETLEN. The new buffer is allocated by xmalloc. - - Return 1 for success. On failure, call error and return 0. */ - -int -rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen) - const char *name; - char *textbuf; - size_t textlen; - const char *diffbuf; - size_t difflen; - char **retbuf; - size_t *retlen; -{ - struct linevector lines; - int ret; - - *retbuf = NULL; - *retlen = 0; - - linevector_init (&lines); - - if (! linevector_add (&lines, textbuf, textlen, NULL, 0)) - error (1, 0, "cannot initialize line vector"); - - if (! apply_rcs_changes (&lines, diffbuf, difflen, name, NULL, NULL)) - { - error (0, 0, "invalid change text in %s", name); - ret = 0; - } - else - { - char *p; - size_t n; - unsigned int ln; - - n = 0; - for (ln = 0; ln < lines.nlines; ++ln) - /* 1 for \n */ - n += lines.vector[ln]->len + 1; - - p = xmalloc (n); - *retbuf = p; - - for (ln = 0; ln < lines.nlines; ++ln) - { - memcpy (p, lines.vector[ln]->text, lines.vector[ln]->len); - p += lines.vector[ln]->len; - if (lines.vector[ln]->has_newline) - *p++ = '\n'; - } - - *retlen = p - *retbuf; - assert (*retlen <= n); - - ret = 1; - } - - linevector_free (&lines); - - return ret; -} - -/* Walk the deltas in RCS to get to revision VERSION. - - If OP is RCS_ANNOTATE, then write annotations using cvs_output. - - If OP is RCS_FETCH, then put the contents of VERSION into a - newly-malloc'd array and put a pointer to it in *TEXT. Each line - is \n terminated; the caller is responsible for converting text - files if desired. The total length is put in *LEN. - - If FP is non-NULL, it should be a file descriptor open to the file - RCS with file position pointing to the deltas. We close the file - when we are done. - - If LOG is non-NULL, then *LOG is set to the log message of VERSION, - and *LOGLEN is set to the length of the log message. - - On error, give a fatal error. */ - -void -RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen) - RCSNode *rcs; - FILE *fp; - struct rcsbuffer *rcsbuf; - const char *version; - enum rcs_delta_op op; - char **text; - size_t *len; - char **log; - size_t *loglen; -{ - struct rcsbuffer rcsbuf_local; - char *branchversion; - char *cpversion; - char *key; - char *value; - size_t vallen; - RCSVers *vers; - RCSVers *prev_vers; - RCSVers *trunk_vers; - char *next; - int ishead, isnext, isversion, onbranch; - Node *node; - struct linevector headlines; - struct linevector curlines; - struct linevector trunklines; - int foundhead; - - assert (version); - - if (fp == NULL) - { - rcsbuf_cache_open (rcs, rcs->delta_pos, &fp, &rcsbuf_local); - rcsbuf = &rcsbuf_local; - } - - assert (rcsbuf); - - if (log) *log = NULL; - - ishead = 1; - vers = NULL; - prev_vers = NULL; - trunk_vers = NULL; - next = NULL; - onbranch = 0; - foundhead = 0; - - linevector_init (&curlines); - linevector_init (&headlines); - linevector_init (&trunklines); - - /* We set BRANCHVERSION to the version we are currently looking - for. Initially, this is the version on the trunk from which - VERSION branches off. If VERSION is not a branch, then - BRANCHVERSION is just VERSION. */ - branchversion = xstrdup (version); - cpversion = strchr (branchversion, '.'); - if (cpversion != NULL) - cpversion = strchr (cpversion + 1, '.'); - if (cpversion != NULL) - *cpversion = '\0'; - - do { - if (! rcsbuf_getrevnum (rcsbuf, &key)) - error (1, 0, "unexpected EOF reading RCS file %s", rcs->path); - - /* look up the revision */ - node = findnode (rcs->versions, key); - if (!node) - error (1, 0, - "Delta text %s without revision information in `%s'.", - key, rcs->path); - - if (next != NULL && ! STREQ (next, key)) - { - /* This is not the next version we need. It is a branch - version which we want to ignore. */ - isnext = 0; - isversion = 0; - } - else - { - isnext = 1; - - /* Stash the previous version. */ - prev_vers = vers; - - vers = node->data; - next = vers->next; - - /* Compare key and trunkversion now, because key points to - storage controlled by rcsbuf_getkey. */ - if (STREQ (branchversion, key)) - isversion = 1; - else - isversion = 0; - } - - while (1) - { - if (! rcsbuf_getkey (rcsbuf, &key, &value)) - error (1, 0, "%s does not appear to be a valid rcs file", - rcs->path); - - if (log != NULL - && isversion - && STREQ (key, "log") - && STREQ (branchversion, version)) - { - if (*log != NULL) - { - error (0, 0, "Duplicate `log' keyword in RCS file (`%s').", - rcs->path); - free (*log); - } - *log = rcsbuf_valcopy (rcsbuf, value, 0, loglen); - } - - if (STREQ (key, "text")) - { - rcsbuf_valpolish (rcsbuf, value, 0, &vallen); - if (ishead) - { - if (! linevector_add (&curlines, value, vallen, NULL, 0)) - error (1, 0, "invalid rcs file %s", rcs->path); - - ishead = 0; - } - else if (isnext) - { - if (! apply_rcs_changes (&curlines, value, vallen, - rcs->path, - onbranch ? vers : NULL, - onbranch ? NULL : prev_vers)) - error (1, 0, "invalid change text in %s", rcs->path); - } - break; - } - } - - if (isversion) - { - /* This is either the version we want, or it is the - branchpoint to the version we want. */ - if (STREQ (branchversion, version)) - { - /* This is the version we want. */ - linevector_copy (&headlines, &curlines); - foundhead = 1; - if (onbranch) - { - /* We have found this version by tracking up a - branch. Restore back to the lines we saved - when we left the trunk, and continue tracking - down the trunk. */ - onbranch = 0; - vers = trunk_vers; - next = vers->next; - linevector_copy (&curlines, &trunklines); - } - } - else - { - Node *p; - - /* We need to look up the branch. */ - onbranch = 1; - - if (numdots (branchversion) < 2) - { - unsigned int ln; - - /* We are leaving the trunk; save the current - lines so that we can restore them when we - continue tracking down the trunk. */ - trunk_vers = vers; - linevector_copy (&trunklines, &curlines); - - /* Reset the version information we have - accumulated so far. It only applies to the - changes from the head to this version. */ - for (ln = 0; ln < curlines.nlines; ++ln) - curlines.vector[ln]->vers = NULL; - } - - /* The next version we want is the entry on - VERS->branches which matches this branch. For - example, suppose VERSION is 1.21.4.3 and - BRANCHVERSION was 1.21. Then we look for an entry - starting with "1.21.4" and we'll put it (probably - 1.21.4.1) in NEXT. We'll advance BRANCHVERSION by - two dots (in this example, to 1.21.4.3). */ - - if (vers->branches == NULL) - error (1, 0, "missing expected branches in %s", - rcs->path); - if (!cpversion) - error (1, 0, "Invalid revision number in `%s'.", - rcs->path); - *cpversion = '.'; - ++cpversion; - cpversion = strchr (cpversion, '.'); - if (cpversion == NULL) - error (1, 0, "version number confusion in %s", - rcs->path); - for (p = vers->branches->list->next; - p != vers->branches->list; - p = p->next) - if (strncmp (p->key, branchversion, - cpversion - branchversion) == 0) - break; - if (p == vers->branches->list) - error (1, 0, "missing expected branch in %s", - rcs->path); - - next = p->key; - - cpversion = strchr (cpversion + 1, '.'); - if (cpversion != NULL) - *cpversion = '\0'; - } - } - if (op == RCS_FETCH && foundhead) - break; - } while (next != NULL); - - free (branchversion); - - rcsbuf_cache (rcs, rcsbuf); - - if (! foundhead) - error (1, 0, "could not find desired version %s in %s", - version, rcs->path); - - /* Now print out or return the data we have just computed. */ - switch (op) - { - case RCS_ANNOTATE: - { - unsigned int ln; - - for (ln = 0; ln < headlines.nlines; ++ln) - { - char *buf; - /* Period which separates year from month in date. */ - char *ym; - /* Period which separates month from day in date. */ - char *md; - RCSVers *prvers; - - prvers = headlines.vector[ln]->vers; - if (prvers == NULL) - prvers = vers; - - buf = xmalloc (strlen (prvers->version) + 24); - sprintf (buf, "%-12s (%-8.8s ", - prvers->version, - prvers->author); - cvs_output (buf, 0); - free (buf); - - /* Now output the date. */ - ym = strchr (prvers->date, '.'); - if (ym == NULL) - { - /* ??- is an ANSI trigraph. The ANSI way to - avoid it is \? but some pre ANSI compilers - complain about the unrecognized escape - sequence. Of course string concatenation - ("??" "-???") is also an ANSI-ism. Testing - __STDC__ seems to be a can of worms, since - compilers do all kinds of things with it. */ - cvs_output ("??", 0); - cvs_output ("-???", 0); - cvs_output ("-??", 0); - } - else - { - md = strchr (ym + 1, '.'); - if (md == NULL) - cvs_output ("??", 0); - else - cvs_output (md + 1, 2); - - cvs_output ("-", 1); - cvs_output (month_printname (ym + 1), 0); - cvs_output ("-", 1); - /* Only output the last two digits of the year. Our output - lines are long enough as it is without printing the - century. */ - cvs_output (ym - 2, 2); - } - cvs_output ("): ", 0); - if (headlines.vector[ln]->len != 0) - cvs_output (headlines.vector[ln]->text, - headlines.vector[ln]->len); - cvs_output ("\n", 1); - } - } - break; - case RCS_FETCH: - { - char *p; - size_t n; - unsigned int ln; - - assert (text != NULL); - assert (len != NULL); - - n = 0; - for (ln = 0; ln < headlines.nlines; ++ln) - /* 1 for \n */ - n += headlines.vector[ln]->len + 1; - p = xmalloc (n); - *text = p; - for (ln = 0; ln < headlines.nlines; ++ln) - { - memcpy (p, headlines.vector[ln]->text, - headlines.vector[ln]->len); - p += headlines.vector[ln]->len; - if (headlines.vector[ln]->has_newline) - *p++ = '\n'; - } - *len = p - *text; - assert (*len <= n); - } - break; - } - - linevector_free (&curlines); - linevector_free (&headlines); - linevector_free (&trunklines); - - return; -} - -/* Read the information for a single delta from the RCS buffer RCSBUF, - whose name is RCSFILE. *KEYP and *VALP are either NULL, or the - first key/value pair to read, as set by rcsbuf_getkey. Return NULL - if there are no more deltas. Store the key/value pair which - terminated the read in *KEYP and *VALP. */ - -static RCSVers * -getdelta (rcsbuf, rcsfile, keyp, valp) - struct rcsbuffer *rcsbuf; - char *rcsfile; - char **keyp; - char **valp; -{ - RCSVers *vnode; - char *key, *value, *cp; - Node *kv; - - /* Get revision number if it wasn't passed in. This uses - rcsbuf_getkey because it doesn't croak when encountering - unexpected input. As a result, we have to play unholy games - with `key' and `value'. */ - if (*keyp != NULL) - { - key = *keyp; - value = *valp; - } - else - { - if (! rcsbuf_getkey (rcsbuf, &key, &value)) - error (1, 0, "%s: unexpected EOF", rcsfile); - } - - /* Make sure that it is a revision number and not a cabbage - or something. */ - for (cp = key; - (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0'; - cp++) - /* do nothing */ ; - /* Note that when comparing with RCSDATE, we are not massaging - VALUE from the string found in the RCS file. This is OK since - we know exactly what to expect. */ - if (*cp != '\0' || strncmp (RCSDATE, value, (sizeof RCSDATE) - 1) != 0) - { - *keyp = key; - *valp = value; - return NULL; - } - - vnode = (RCSVers *) xmalloc (sizeof (RCSVers)); - memset (vnode, 0, sizeof (RCSVers)); - - vnode->version = xstrdup (key); - - /* Grab the value of the date from value. Note that we are not - massaging VALUE from the string found in the RCS file. */ - cp = value + (sizeof RCSDATE) - 1; /* skip the "date" keyword */ - while (whitespace (*cp)) /* take space off front of value */ - cp++; - - vnode->date = xstrdup (cp); - - /* Get author field. */ - if (! rcsbuf_getkey (rcsbuf, &key, &value)) - { - error (1, 0, "unexpected end of file reading %s", rcsfile); - } - if (! STREQ (key, "author")) - error (1, 0, "\ -unable to parse %s; `author' not in the expected place", rcsfile); - vnode->author = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); - - /* Get state field. */ - if (! rcsbuf_getkey (rcsbuf, &key, &value)) - { - error (1, 0, "unexpected end of file reading %s", rcsfile); - } - if (! STREQ (key, "state")) - error (1, 0, "\ -unable to parse %s; `state' not in the expected place", rcsfile); - vnode->state = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); - /* The value is optional, according to rcsfile(5). */ - if (value != NULL && STREQ (value, RCSDEAD)) - { - vnode->dead = 1; - } - - /* Note that "branches" and "next" are in fact mandatory, according - to doc/RCSFILES. */ - - /* fill in the branch list (if any branches exist) */ - if (! rcsbuf_getkey (rcsbuf, &key, &value)) - { - error (1, 0, "unexpected end of file reading %s", rcsfile); - } - if (STREQ (key, RCSDESC)) - { - *keyp = key; - *valp = value; - /* Probably could/should be a fatal error. */ - error (0, 0, "warning: 'branches' keyword missing from %s", rcsfile); - return vnode; - } - if (value != (char *) NULL) - { - vnode->branches = getlist (); - /* Note that we are not massaging VALUE from the string found - in the RCS file. */ - do_branches (vnode->branches, value); - } - - /* fill in the next field if there is a next revision */ - if (! rcsbuf_getkey (rcsbuf, &key, &value)) - { - error (1, 0, "unexpected end of file reading %s", rcsfile); - } - if (STREQ (key, RCSDESC)) - { - *keyp = key; - *valp = value; - /* Probably could/should be a fatal error. */ - error (0, 0, "warning: 'next' keyword missing from %s", rcsfile); - return vnode; - } - if (value != (char *) NULL) - vnode->next = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); - - /* - * XXX - this is where we put the symbolic link stuff??? - * (into newphrases in the deltas). - */ - while (1) - { - if (! rcsbuf_getkey (rcsbuf, &key, &value)) - error (1, 0, "unexpected end of file reading %s", rcsfile); - - /* 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 (strcmp (key, "hardlinks") == 0) - { - char *word; - - vnode->hardlinks = getlist(); - while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL) - { - Node *n = getnode(); - n->key = word; - addnode (vnode->hardlinks, n); - } - continue; - } -#endif - - /* 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 - checking for it is harmless. */ - if (STREQ (key, RCSDEAD)) - { - vnode->dead = 1; - if (vnode->state != NULL) - free (vnode->state); - vnode->state = xstrdup (RCSDEAD); - continue; - } - /* if we have a new revision number, we're done with this delta */ - for (cp = key; - (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0'; - cp++) - /* do nothing */ ; - /* Note that when comparing with RCSDATE, we are not massaging - VALUE from the string found in the RCS file. This is OK - since we know exactly what to expect. */ - if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0) - break; - - /* At this point, key and value represent a user-defined field - in the delta node. */ - if (vnode->other_delta == NULL) - vnode->other_delta = getlist (); - kv = getnode (); - 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 - questionable, in that we don't know what they mean and - doc/RCSFILES has no prohibition on several newphrases - with the same key. But we can't store more than one as - long as we store them in a List *. */ - error (0, 0, "warning: duplicate key `%s' in RCS file `%s'", - key, rcsfile); - freenode (kv); - } - } - - /* Return the key which caused us to fail back to the caller. */ - *keyp = key; - *valp = value; - - return vnode; -} - -static void -freedeltatext (d) - Deltatext *d; -{ - if (d->version != NULL) - free (d->version); - if (d->log != NULL) - free (d->log); - if (d->text != NULL) - free (d->text); - if (d->other != (List *) NULL) - dellist (&d->other); - free (d); -} - -static Deltatext * -RCS_getdeltatext (rcs, fp, rcsbuf) - RCSNode *rcs; - FILE *fp; - struct rcsbuffer *rcsbuf; -{ - char *num; - char *key, *value; - Node *p; - Deltatext *d; - - /* Get the revision number. */ - if (! rcsbuf_getrevnum (rcsbuf, &num)) - { - /* If num == NULL, it means we reached EOF naturally. That's - fine. */ - if (num == NULL) - return NULL; - else - error (1, 0, "%s: unexpected EOF", rcs->path); - } - - p = findnode (rcs->versions, num); - if (!p) - error (1, 0, - "Delta text %s without revision information in `%s'.", - num, rcs->path); - - d = (Deltatext *) xmalloc (sizeof (Deltatext)); - d->version = xstrdup (num); - - /* Get the log message. */ - if (! rcsbuf_getkey (rcsbuf, &key, &value)) - error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num); - if (! STREQ (key, "log")) - error (1, 0, "%s, delta %s: expected `log', got `%s'", - rcs->path, num, key); - d->log = rcsbuf_valcopy (rcsbuf, value, 0, (size_t *) NULL); - - /* Get random newphrases. */ - d->other = getlist(); - while (1) - { - if (! rcsbuf_getkey (rcsbuf, &key, &value)) - error (1, 0, "%s, delta %s: unexpected EOF", rcs->path, num); - - if (STREQ (key, "text")) - break; - - p = getnode(); - p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD; - p->key = xstrdup (key); - 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'", - rcs->path, num, key); - } - } - - /* Get the change text. We already know that this key is `text'. */ - d->text = rcsbuf_valcopy (rcsbuf, value, 0, &d->len); - - return d; -} - -/* RCS output functions, for writing RCS format files from RCSNode - structures. - - For most of this work, RCS 5.7 uses an `aprintf' function which aborts - program upon error. Instead, these functions check the output status - of the stream right before closing it, and aborts if an error condition - is found. The RCS solution is probably the better one: it produces - more overhead, but will produce a clearer diagnostic in the case of - catastrophic error. In either case, however, the repository will probably - not get corrupted. */ - -static int -putsymbol_proc (symnode, fparg) - Node *symnode; - void *fparg; -{ - FILE *fp = (FILE *) fparg; - - /* A fiddly optimization: this code used to just call fprintf, but - in an old repository with hundreds of tags this can get called - hundreds of thousands of times when doing a cvs tag. Since - tagging is a relatively common operation, and using putc and - fputs is just as comprehensible, the change is worthwhile. */ - putc ('\n', fp); - putc ('\t', fp); - fputs (symnode->key, fp); - putc (':', fp); - fputs (symnode->data, fp); - return 0; -} - -static int putlock_proc PROTO ((Node *, void *)); - -/* putlock_proc is like putsymbol_proc, but key and data are reversed. */ - -static int -putlock_proc (symnode, fp) - Node *symnode; - void *fp; -{ - return fprintf ((FILE *) fp, "\n\t%s:%s", (char *)symnode->data, symnode->key); -} - -static int -putrcsfield_proc (node, vfp) - Node *node; - void *vfp; -{ - FILE *fp = (FILE *) vfp; - - /* Some magic keys used internally by CVS start with `;'. Skip them. */ - if (node->key[0] == ';') - return 0; - - fprintf (fp, "\n%s\t", node->key); - if (node->data != NULL) - { - /* If the field's value contains evil characters, - it must be stringified. */ - /* FIXME: This does not quite get it right. "7jk8f" is not a legal - value for a value in a newpharse, according to doc/RCSFILES, - because digits are not valid in an "id". We might do OK by - always writing strings (enclosed in @@). Would be nice to - explicitly mention this one way or another in doc/RCSFILES. - 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. */ - - if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL) - fputs (node->data, fp); - else - { - putc ('@', fp); - expand_at_signs (node->data, (off_t) strlen (node->data), fp); - putc ('@', fp); - } - } - - /* desc, log and text fields should not be terminated with semicolon; - all other fields should be. */ - if (! STREQ (node->key, "desc") && - ! STREQ (node->key, "log") && - ! STREQ (node->key, "text")) - { - putc (';', fp); - } - return 0; -} - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - -/* Save a filename in a `hardlinks' RCS field. NODE->KEY will contain - a full pathname, but currently only basenames are stored in the RCS - node. Assume that the filename includes nasty characters and - @-escape it. */ - -static int -puthardlink_proc (node, vfp) - Node *node; - void *vfp; -{ - FILE *fp = (FILE *) vfp; - char *basename = strrchr (node->key, '/'); - - if (basename == NULL) - basename = node->key; - else - ++basename; - - putc ('\t', fp); - putc ('@', fp); - (void) expand_at_signs (basename, strlen (basename), fp); - putc ('@', fp); - - return 0; -} - -#endif - -/* Output the admin node for RCS into stream FP. */ - -static void -RCS_putadmin (rcs, fp) - RCSNode *rcs; - FILE *fp; -{ - fprintf (fp, "%s\t%s;\n", RCSHEAD, rcs->head ? rcs->head : ""); - if (rcs->branch) - fprintf (fp, "%s\t%s;\n", RCSBRANCH, rcs->branch); - - fputs ("access", fp); - if (rcs->access) - { - char *p, *s; - s = xstrdup (rcs->access); - for (p = strtok (s, " \n\t"); p != NULL; p = strtok (NULL, " \n\t")) - fprintf (fp, "\n\t%s", p); - free (s); - } - fputs (";\n", fp); - - fputs (RCSSYMBOLS, fp); - /* If we haven't had to convert the symbols to a list yet, don't - force a conversion now; just write out the string. */ - if (rcs->symbols == NULL && rcs->symbols_data != NULL) - { - fputs ("\n\t", fp); - fputs (rcs->symbols_data, fp); - } - else - walklist (RCS_symbols (rcs), putsymbol_proc, (void *) fp); - fputs (";\n", fp); - - fputs ("locks", fp); - if (rcs->locks_data) - fprintf (fp, "\t%s", rcs->locks_data); - else if (rcs->locks) - walklist (rcs->locks, putlock_proc, (void *) fp); - if (rcs->strict_locks) - fprintf (fp, "; strict"); - fputs (";\n", fp); - - if (rcs->comment) - { - fprintf (fp, "comment\t@"); - expand_at_signs (rcs->comment, (off_t) strlen (rcs->comment), fp); - fputs ("@;\n", fp); - } - if (rcs->expand && ! STREQ (rcs->expand, "kv")) - fprintf (fp, "%s\t@%s@;\n", RCSEXPAND, rcs->expand); - - walklist (rcs->other, putrcsfield_proc, (void *) fp); - - putc ('\n', fp); -} - -static void -putdelta (vers, fp) - RCSVers *vers; - FILE *fp; -{ - Node *bp, *start; - - /* Skip if no revision was supplied, or if it is outdated (cvs admin -o) */ - if (vers == NULL || vers->outdated) - return; - - fprintf (fp, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches", - vers->version, - RCSDATE, vers->date, - "author", vers->author, - "state", vers->state ? vers->state : ""); - - if (vers->branches != NULL) - { - start = vers->branches->list; - for (bp = start->next; bp != start; bp = bp->next) - fprintf (fp, "\n\t%s", bp->key); - } - - fprintf (fp, ";\nnext\t%s;", vers->next ? vers->next : ""); - - walklist (vers->other_delta, putrcsfield_proc, fp); - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - if (vers->hardlinks) - { - fprintf (fp, "\nhardlinks"); - walklist (vers->hardlinks, puthardlink_proc, fp); - putc (';', fp); - } -#endif - putc ('\n', fp); -} - -static void -RCS_putdtree (rcs, rev, fp) - RCSNode *rcs; - char *rev; - FILE *fp; -{ - RCSVers *versp; - Node *p, *branch; - - /* Previously, this function used a recursive implementation, but - if the trunk has a huge number of revisions and the program - stack is not big, a stack overflow could occur, so this - nonrecursive version was developed to be more safe. */ - Node *branchlist, *onebranch; - List *branches; - List *onebranchlist; - - if (rev == NULL) - return; - - branches = getlist(); - - for (; rev != NULL;) - { - /* Find the delta node for this revision. */ - p = findnode (rcs->versions, rev); - if (p == NULL) - { - error (1, 0, - "error parsing repository file %s, file may be corrupt.", - rcs->path); - } - - versp = p->data; - - /* Print the delta node and go for its `next' node. This - prints the trunk. If there are any branches printed on this - revision, mark we have some. */ - putdelta (versp, fp); - /* Store branch information into branch list so to write its - trunk afterwards */ - if (versp->branches != NULL) - { - branch = getnode(); - branch->data = versp->branches; - - addnode(branches, branch); - } - - rev = versp->next; - } - - /* If there are any branches printed on this revision, - print those trunks as well. */ - branchlist = branches->list; - for (branch = branchlist->next; - branch != branchlist; - branch = branch->next) - { - onebranchlist = (List *)(branch->data); - onebranch = onebranchlist->list; - for (p = onebranch->next; p != onebranch; p = p->next) - RCS_putdtree (rcs, p->key, fp); - - branch->data = NULL; /* so to prevent its freeing on dellist */ - } - - dellist(&branches); -} - -static void -RCS_putdesc (rcs, fp) - RCSNode *rcs; - FILE *fp; -{ - fprintf (fp, "\n\n%s\n@", RCSDESC); - if (rcs->desc != NULL) - { - off_t len = (off_t) strlen (rcs->desc); - if (len > 0) - { - expand_at_signs (rcs->desc, len, fp); - if (rcs->desc[len-1] != '\n') - putc ('\n', fp); - } - } - fputs ("@\n", fp); -} - -static void -putdeltatext (fp, d) - FILE *fp; - Deltatext *d; -{ - fprintf (fp, "\n\n%s\nlog\n@", d->version); - if (d->log != NULL) - { - int loglen = strlen (d->log); - expand_at_signs (d->log, (off_t) loglen, fp); - if (d->log[loglen-1] != '\n') - putc ('\n', fp); - } - putc ('@', fp); - - walklist (d->other, putrcsfield_proc, fp); - - fputs ("\ntext\n@", fp); - if (d->text != NULL) - expand_at_signs (d->text, (off_t) d->len, fp); - fputs ("@\n", fp); -} - -/* TODO: the whole mechanism for updating deltas is kludgey... more - sensible would be to supply all the necessary info in a `newdeltatext' - field for RCSVers nodes. -twp */ - -/* Copy delta text nodes from FIN to FOUT. If NEWDTEXT is non-NULL, it - is a new delta text node, and should be added to the tree at the - node whose revision number is INSERTPT. (Note that trunk nodes are - written in decreasing order, and branch nodes are written in - increasing order.) */ - -static void -RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt) - RCSNode *rcs; - FILE *fin; - struct rcsbuffer *rcsbufin; - FILE *fout; - Deltatext *newdtext; - char *insertpt; -{ - int actions; - RCSVers *dadmin; - Node *np; - int insertbefore, found; - char *bufrest; - int nls; - size_t buflen; - char buf[8192]; - int got; - - /* Count the number of versions for which we have to do some - special operation. */ - actions = walklist (rcs->versions, count_delta_actions, (void *) NULL); - - /* Make a note of whether NEWDTEXT should be inserted - before or after its INSERTPT. */ - insertbefore = (newdtext != NULL && numdots (newdtext->version) == 1); - - while (actions != 0 || newdtext != NULL) - { - Deltatext *dtext; - - dtext = RCS_getdeltatext (rcs, fin, rcsbufin); - - /* We shouldn't hit EOF here, because that would imply that - some action was not taken, or that we could not insert - NEWDTEXT. */ - if (dtext == NULL) - error (1, 0, "internal error: EOF too early in RCS_copydeltas"); - - found = (insertpt != NULL && STREQ (dtext->version, insertpt)); - if (found && insertbefore) - { - putdeltatext (fout, newdtext); - newdtext = NULL; - insertpt = NULL; - } - - np = findnode (rcs->versions, dtext->version); - if (!np) - error (1, 0, - "Delta text %s without revision information in `%s'.", - dtext->version, rcs->path); - - dadmin = np->data; - - /* If this revision has been outdated, just skip it. */ - if (dadmin->outdated) - { - freedeltatext (dtext); - --actions; - continue; - } - - /* Update the change text for this delta. New change text - data may come from cvs admin -m, cvs admin -o, or cvs ci. */ - if (dadmin->text != NULL) - { - if (dadmin->text->log != NULL || dadmin->text->text != NULL) - --actions; - if (dadmin->text->log != NULL) - { - free (dtext->log); - dtext->log = dadmin->text->log; - dadmin->text->log = NULL; - } - if (dadmin->text->text != NULL) - { - free (dtext->text); - dtext->text = dadmin->text->text; - dtext->len = dadmin->text->len; - dadmin->text->text = NULL; - } - } - putdeltatext (fout, dtext); - freedeltatext (dtext); - - if (found && !insertbefore) - { - putdeltatext (fout, newdtext); - newdtext = NULL; - insertpt = NULL; - } - } - - /* Copy the rest of the file directly, without bothering to - interpret it. The caller will handle error checking by calling - ferror. - - We just wrote a newline to the file, either in putdeltatext or - in the caller. However, we may not have read the corresponding - newline from the file, because rcsbuf_getkey returns as soon as - it finds the end of the '@' string for the desc or text key. - Therefore, we may read three newlines when we should really - only write two, and we check for that case here. This is not - an semantically important issue; we only do it to make our RCS - files look traditional. */ - - nls = 3; - - rcsbuf_get_buffered (rcsbufin, &bufrest, &buflen); - if (buflen > 0) - { - if (bufrest[0] != '\n' - || strncmp (bufrest, "\n\n\n", buflen < 3 ? buflen : 3) != 0) - { - nls = 0; - } - else - { - if (buflen < 3) - nls -= buflen; - else - { - ++bufrest; - --buflen; - nls = 0; - } - } - - fwrite (bufrest, 1, buflen, fout); - } - if (!rcsbufin->mmapped) - { - /* This bit isn't necessary when using mmap since the entire file - * will already be available via the RCS buffer. Besides, the - * mmap code doesn't always keep the file pointer up to date, so - * this adds some data twice. - */ - while ((got = fread (buf, 1, sizeof buf, fin)) != 0) - { - if (nls > 0 - && got >= nls - && buf[0] == '\n' - && strncmp (buf, "\n\n\n", nls) == 0) - { - fwrite (buf + 1, 1, got - 1, fout); - } - else - { - fwrite (buf, 1, got, fout); - } - - nls = 0; - } - } -} - -/* A helper procedure for RCS_copydeltas. This is called via walklist - to count the number of RCS revisions for which some special action - is required. */ - -static int -count_delta_actions (np, ignore) - Node *np; - void *ignore; -{ - RCSVers *dadmin = np->data; - - if (dadmin->outdated) - return 1; - - if (dadmin->text != NULL - && (dadmin->text->log != NULL || dadmin->text->text != NULL)) - { - return 1; - } - - return 0; -} - -/* - * Clean up temporary files - */ -RETSIGTYPE -rcs_cleanup () -{ - /* Note that the checks for existence_error are because we are - called from a signal handler, so we don't know whether the - files got created. */ - - /* FIXME: Do not perform buffered I/O from an interrupt handler like - this (via error). However, I'm leaving the error-calling code there - in the hope that on the rare occasion the error call is actually made - (e.g., a fluky I/O error or permissions problem prevents the deletion - of a just-created file) reentrancy won't be an issue. */ - if (rcs_lockfile != NULL) - { - 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", tmp); - } -} - -/* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style - locking on the specified RCSFILE: for a file called `foo,v', open - for writing a file called `,foo,'. - - Note that we what do here is quite different from what RCS does. - RCS creates the ,foo, file before it reads the RCS file (if it - knows that it will be writing later), so that it actually serves as - a lock. We don't; instead we rely on CVS writelocks. This means - that if someone is running RCS on the file at the same time they - are running CVS on it, they might lose (we read the file, - then RCS writes it, then we write it, clobbering the - changes made by RCS). I believe the current sentiment about this - is "well, don't do that". - - A concern has been expressed about whether adopting the RCS - strategy would slow us down. I don't think so, since we need to - write the ,foo, file anyway (unless perhaps if O_EXCL is slower or - something). - - These do not perform quite the same function as the RCS -l option - for locking files: they are intended to prevent competing RCS - processes from stomping all over each other's laundry. Hence, - they are `internal' locking functions. - - If there is an error, give a fatal error; if we return we always - return a non-NULL value. */ - -static FILE * -rcs_internal_lockfile (rcsfile) - char *rcsfile; -{ - struct stat rstat; - FILE *fp; - static int first_call = 1; - - if (first_call) - { - 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 -#ifdef SIGINT - (void) SIG_register (SIGINT, rcs_cleanup); -#endif -#ifdef SIGQUIT - (void) SIG_register (SIGQUIT, rcs_cleanup); -#endif -#ifdef SIGPIPE - (void) SIG_register (SIGPIPE, rcs_cleanup); -#endif -#ifdef SIGTERM - (void) SIG_register (SIGTERM, rcs_cleanup); -#endif - } - - /* 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 - file. (Really, this is a lie -- if this is a new file, - RCS_checkin uses the permissions from the working copy. For - actually creating the file, we use 0444 as a safe default mode.) */ - if (stat (rcsfile, &rstat) < 0) - { - if (existence_error (errno)) - rstat.st_mode = S_IRUSR | S_IRGRP | S_IROTH; - else - error (1, errno, "cannot stat %s", rcsfile); - } - - /* Try to open exclusively. POSIX.1 guarantees that O_EXCL|O_CREAT - guarantees an exclusive open. According to the RCS source, with - NFS v2 we must also throw in O_TRUNC and use an open mask that makes - the file unwriteable. For extensive justification, see the comments for - rcswriteopen() in rcsedit.c, in RCS 5.7. This is kind of pointless - in the CVS case; see comment at the start of this file concerning - general ,foo, file strategy. - - There is some sentiment that with NFSv3 and such, that one can - 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. */ - rcs_lockfd = open (rcs_lockfile, - OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, - S_IRUSR | S_IRGRP | S_IROTH); - - if (rcs_lockfd < 0) - { - error (1, errno, "could not open lock file `%s'", rcs_lockfile); - } - - /* Force the file permissions, and return a stream object. */ - /* Because we change the modes later, we don't worry about - this in the non-HAVE_FCHMOD case. */ -#ifdef HAVE_FCHMOD - if (fchmod (rcs_lockfd, rstat.st_mode) < 0) - error (1, errno, "cannot change mode for %s", rcs_lockfile); -#endif - fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE); - if (fp == NULL) - error (1, errno, "cannot fdopen %s", rcs_lockfile); - - return fp; -} - -static void -rcs_internal_unlockfile (fp, rcsfile) - FILE *fp; - 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 - corrupting the repository. */ - - if (ferror (fp)) - /* Using errno here may well be misleanding since the most recent - call that set errno may not have anything whatsoever to do with - the error that set the flag, but it's better than nothing. The - real solution is to check each call to fprintf rather than waiting - until the end like this. */ - error (1, errno, "error writing to lock file %s", rcs_lockfile); - - /* Flush and sync the file, or the user may be told the commit completed, - * while a server crash/power failure could still cause the data to be - * lost. - * - * Invoking rename(",<file>," , "<file>,v") on Linux and almost all UNIXs - * only flushes the inode for the target file to disk, it does not - * guarantee flush of the kernel buffers allocated for the ,<file>,. - * Depending upon the load on the machine, the Linux kernel's flush daemon - * process may not flush for a while. In the meantime the CVS transaction - * could have been declared committed to the end CVS user (CVS process has - * returned the final "OK"). If the machine crashes prior to syncing the - * changes to disk, the committed transaction can be lost. - */ - if (fflush (fp) != 0) - error (1, errno, "error flushing file `%s' to kernel buffers", - rcs_lockfile); -#ifdef HAVE_FSYNC - if (fsync (rcs_lockfd) < 0) - error (1, errno, "error fsyncing file `%s'", rcs_lockfile); -#endif - - if (fclose (fp) == EOF) - error (1, errno, "error closing lock file %s", rcs_lockfile); - rcs_lockfd = -1; - - rename_file (rcs_lockfile, rcsfile); - - { - /* Use a temporary to make sure there's no interval - (after rcs_lockfile has been freed but before it's set to NULL) - during which the signal handler's use of rcs_lockfile would - reference freed memory. */ - char *tmp = rcs_lockfile; - rcs_lockfile = NULL; - free (tmp); - } -} - -static char * -rcs_lockfilename (rcsfile) - const char *rcsfile; -{ - char *lockfile, *lockp; - const char *rcsbase, *rcsp, *rcsend; - int rcslen; - - /* Create the lockfile name. */ - rcslen = strlen (rcsfile); - lockfile = (char *) xmalloc (rcslen + 10); - rcsbase = last_component (rcsfile); - rcsend = rcsfile + rcslen - sizeof(RCSEXT); - for (lockp = lockfile, rcsp = rcsfile; rcsp < rcsbase; ++rcsp) - *lockp++ = *rcsp; - *lockp++ = ','; - while (rcsp <= rcsend) - *lockp++ = *rcsp++; - *lockp++ = ','; - *lockp = '\0'; - - return lockfile; -} - -/* Rewrite an RCS file. The basic idea here is that the caller should - first call RCS_reparsercsfile, then munge the data structures as - desired (via RCS_delete_revs, RCS_settag, &c), then call RCS_rewrite. */ - -void -RCS_rewrite (rcs, newdtext, insertpt) - RCSNode *rcs; - Deltatext *newdtext; - char *insertpt; -{ - FILE *fin, *fout; - struct rcsbuffer rcsbufin; - - assert (rcs); - - if (noexec) - return; - - /* Make sure we're operating on an actual file and not a symlink. */ - resolve_symlink (&(rcs->path)); - - fout = rcs_internal_lockfile (rcs->path); - - RCS_putadmin (rcs, fout); - RCS_putdtree (rcs, rcs->head, fout); - RCS_putdesc (rcs, fout); - - /* Open the original RCS file and seek to the first delta text. */ - rcsbuf_cache_open (rcs, rcs->delta_pos, &fin, &rcsbufin); - - /* Update delta_pos to the current position in the output file. - Do NOT move these statements: they must be done after fin has - been positioned at the old delta_pos, but before any delta - texts have been written to fout. - */ - rcs->delta_pos = ftell (fout); - if (rcs->delta_pos == -1) - error (1, errno, "cannot ftell in RCS file %s", rcs->path); - - RCS_copydeltas (rcs, fin, &rcsbufin, fout, newdtext, insertpt); - - /* We don't want to call rcsbuf_cache here, since we're about to - delete the file. */ - rcsbuf_close (&rcsbufin); - if (ferror (fin)) - /* The only case in which using errno here would be meaningful - is if we happen to have left errno unmolested since the call - which produced the error (e.g. fread). That is pretty - fragile even if it happens to sometimes be true. The real - solution is to make sure that all the code which reads - from fin checks for errors itself (some does, some doesn't). */ - error (0, 0, "warning: ferror set while rewriting RCS file `%s'", rcs->path); - if (fclose (fin) < 0) - error (0, errno, "warning: closing RCS file `%s'", rcs->path); - - 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; -} - -/* - * For a given file with full pathname PATH and revision number REV, - * produce a file label suitable for passing to diff. The default - * file label as used by RCS 5.7 looks like this: - * - * FILENAME <tab> YYYY/MM/DD <sp> HH:MM:SS <tab> REVNUM - * - * The date and time used are the revision's last checkin date and time. - * If REV is NULL, use the working copy's mtime instead. - * - * /dev/null is not statted but assumed to have been created on the Epoch. - * At least using the POSIX.2 definition of patch, this should cause creation - * of files on platforms such as Windoze where the null IO device isn't named - * /dev/null to be parsed by patch properly. - */ -char * -make_file_label (path, rev, rcs) - const char *path; - const char *rev; - RCSNode *rcs; -{ - char datebuf[MAXDATELEN + 1]; - char *label; - - label = (char *) xmalloc (strlen (path) - + (rev == NULL ? 0 : strlen (rev) + 1) - + MAXDATELEN - + 2); - - if (rev) - { - char date[MAXDATELEN + 1]; - /* revs cannot be attached to /dev/null ... duh. */ - assert (strcmp(DEVNULL, path)); - RCS_getrevtime (rcs, rev, datebuf, 0); - (void) date_to_internet (date, datebuf); - (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev); - } - else - { - struct stat sb; - struct tm *wm; - - if (strcmp(DEVNULL, path)) - { - const char *file = last_component (path); - if (CVS_STAT (file, &sb) < 0) - /* Assume that if the stat fails,then the later read for the - * diff will too. - */ - error (1, errno, "could not get info for `%s'", path); - wm = gmtime (&sb.st_mtime); - } - else - { - time_t t = 0; - wm = gmtime(&t); - } - - (void) tm_to_internet (datebuf, wm); - (void) sprintf (label, "-L%s\t%s", path, datebuf); - } - return label; -} - -void -RCS_setlocalid (arg) - const char *arg; -{ - char *copy, *next, *key; - - copy = xstrdup(arg); - next = copy; - key = strtok(next, "="); - - keywords[KEYWORD_LOCALID].string = xstrdup(key); - keywords[KEYWORD_LOCALID].len = strlen(key); - keywords[KEYWORD_LOCALID].expandit = 1; - - /* options? */ - while (key = strtok(NULL, ",")) { - if (!strcmp(key, keywords[KEYWORD_ID].string)) - keyword_local = KEYWORD_ID; - else if (!strcmp(key, keywords[KEYWORD_HEADER].string)) - keyword_local = KEYWORD_HEADER; - else if (!strcmp(key, keywords[KEYWORD_CVSHEADER].string)) - keyword_local = KEYWORD_CVSHEADER; - else - error(1, 0, "Unknown LocalId mode: %s", key); - } - free(copy); -} - -void -RCS_setincexc (arg) - const char *arg; -{ - char *key; - char *copy, *next; - int include = 0; - struct rcs_keyword *keyword; - - copy = xstrdup(arg); - next = copy; - switch (*next++) { - case 'e': - include = 0; - break; - case 'i': - include = 1; - break; - default: - free(copy); - return; - } - - if (include) - for (keyword = keywords; keyword->string != NULL; keyword++) - { - keyword->expandit = 0; - } - - key = strtok(next, ","); - while (key) { - for (keyword = keywords; keyword->string != NULL; keyword++) { - if (strcmp (keyword->string, key) == 0) - keyword->expandit = include; - } - key = strtok(NULL, ","); - } - free(copy); - return; -} - -#define ATTIC "/" CVSATTIC -static char * -getfullCVSname(CVSname, pathstore) - char *CVSname, **pathstore; -{ - if (current_parsed_root->directory) { - int rootlen; - char *c = NULL; - int alen = sizeof(ATTIC) - 1; - - *pathstore = xstrdup(CVSname); - if ((c = strrchr(*pathstore, '/')) != NULL) { - if (c - *pathstore >= alen) { - if (!strncmp(c - alen, ATTIC, alen)) { - while (*c != '\0') { - *(c - alen) = *c; - c++; - } - *(c - alen) = '\0'; - } - } - } - - rootlen = strlen(current_parsed_root->directory); - if (!strncmp(*pathstore, current_parsed_root->directory, rootlen) && - (*pathstore)[rootlen] == '/') - CVSname = (*pathstore + rootlen + 1); - else - CVSname = (*pathstore); - } - return CVSname; -} diff --git a/contrib/cvs/src/rcs.h b/contrib/cvs/src/rcs.h deleted file mode 100644 index 08b8a5f..0000000 --- a/contrib/cvs/src/rcs.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * RCS source control definitions needed by rcs.c and friends - * - * $FreeBSD$ - */ - -/* 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" -#define RCSHEAD "head" -#define RCSBRANCH "branch" -#define RCSSYMBOLS "symbols" -#define RCSDATE "date" -#define RCSDESC "desc" -#define RCSEXPAND "expand" - -/* Used by the version of death support which resulted from old - versions of CVS (e.g. 1.5 if you define DEATH_SUPPORT and not - DEATH_STATE). Only a hacked up RCS (used by those old versions of - CVS) will put this into RCS files. Considered obsolete. */ -#define RCSDEAD "dead" - -#define DATEFORM "%02d.%02d.%02d.%02d.%02d.%02d" -#define SDATEFORM "%d.%d.%d.%d.%d.%d" - -/* - * Opaque structure definitions used by RCS specific lookup routines - */ -#define VALID 0x1 /* flags field contains valid data */ -#define INATTIC 0x2 /* RCS file is located in the Attic */ -#define PARTIAL 0x4 /* RCS file not completly parsed */ - -/* All the "char *" fields in RCSNode, Deltatext, and RCSVers are - '\0'-terminated (except "text" in Deltatext). This means that we - can't deal with fields containing '\0', which is a limitation that - RCS does not have. Would be nice to fix this some day. */ - -struct rcsnode -{ - /* Reference count for this structure. Used to deal with the - fact that there might be a pointer from the Vers_TS or might - not. Callers who increment this field are responsible for - calling freercsnode when they are done with their reference. */ - int refcount; - - /* Flags (INATTIC, PARTIAL, &c), see above. */ - int flags; - - /* File name of the RCS file. This is not necessarily the name - as specified by the user, but it is a name which can be passed to - system calls and a name which is OK to print in error messages - (the various names might differ in case). */ - char *path; - - /* Value for head keyword from RCS header, or NULL if empty. */ - char *head; - - /* Value for branch keyword from RCS header, or NULL if omitted. */ - char *branch; - - /* Raw data on symbolic revisions. The first time that RCS_symbols is - called, we parse these into ->symbols, and free ->symbols_data. */ - char *symbols_data; - - /* Value for expand keyword from RCS header, or NULL if omitted. */ - char *expand; - - /* List of nodes, the key of which is the symbolic name and the data - of which is the numeric revision that it corresponds to (malloc'd). */ - List *symbols; - - /* List of nodes (type RCSVERS), the key of which the numeric revision - number, and the data of which is an RCSVers * for the revision. */ - List *versions; - - /* Value for access keyword from RCS header, or NULL if empty. - FIXME: RCS_delaccess would also seem to use "" for empty. We - should pick one or the other. */ - char *access; - - /* Raw data on locked revisions. The first time that RCS_getlocks is - called, we parse these into ->locks, and free ->locks_data. */ - char *locks_data; - - /* List of nodes, the key of which is the numeric revision and the - data of which is the user that it corresponds to (malloc'd). */ - List *locks; - - /* Set for the strict keyword from the RCS header. */ - int strict_locks; - - /* Value for the comment keyword from RCS header (comment leader), or - NULL if omitted. */ - char *comment; - - /* Value for the desc field in the RCS file, or NULL if empty. */ - char *desc; - - /* File offset of the first deltatext node, so we can seek there. */ - long delta_pos; - - /* Newphrases from the RCS header. List of nodes, the key of which - is the "id" which introduces the newphrase, and the value of which - is the value from the newphrase. */ - List *other; -}; - -typedef struct rcsnode RCSNode; - -struct deltatext { - char *version; - - /* Log message, or NULL if we do not intend to change the log message - (that is, RCS_copydeltas should just use the log message from the - file). */ - char *log; - - /* Change text, or NULL if we do not intend to change the change text - (that is, RCS_copydeltas should just use the change text from the - file). Note that it is perfectly legal to have log be NULL and - text non-NULL, or vice-versa. */ - char *text; - size_t len; - - /* Newphrase fields from deltatext nodes. FIXME: duplicates the - other field in the rcsversnode, I think. */ - List *other; -}; -typedef struct deltatext Deltatext; - -struct rcsversnode -{ - /* Duplicate of the key by which this structure is indexed. */ - char *version; - - char *date; - char *author; - char *state; - char *next; - int dead; - int outdated; - Deltatext *text; - List *branches; - /* Newphrase fields from deltatext nodes. Also contains ";add" and - ";delete" magic fields (see rcs.c, log.c). I think this is - only used by log.c (where it looks up "log"). Duplicates the - other field in struct deltatext, I think. */ - List *other; - /* Newphrase fields from delta nodes. */ - List *other_delta; -#ifdef PRESERVE_PERMISSIONS_SUPPORT - /* Hard link information for each revision. */ - List *hardlinks; -#endif -}; -typedef struct rcsversnode RCSVers; - -/* - * CVS reserves all even-numbered branches for its own use. "magic" branches - * (see rcs.c) are contained as virtual revision numbers (within symbolic - * tags only) off the RCS_MAGIC_BRANCH, which is 0. CVS also reserves the - * ".1" branch for vendor revisions. So, if you do your own branching, you - * should limit your use to odd branch numbers starting at 3. - */ -#define RCS_MAGIC_BRANCH 0 - -/* The type of a function passed to RCS_checkout. */ -typedef void (*RCSCHECKOUTPROC) PROTO ((void *, const char *, size_t)); - -#ifdef __STDC__ -struct rcsbuffer; -#endif - -/* What RCS_deltas is supposed to do. */ -enum rcs_delta_op {RCS_ANNOTATE, RCS_FETCH}; - -/* - * exported interfaces - */ -RCSNode *RCS_parse PROTO((const char *file, const char *repos)); -RCSNode *RCS_parsercsfile PROTO((const char *rcsfile)); -void RCS_fully_parse PROTO((RCSNode *)); -void RCS_reparsercsfile PROTO((RCSNode *, FILE **, struct rcsbuffer *)); -extern int RCS_setattic PROTO ((RCSNode *, int)); - -char *RCS_check_kflag PROTO((const char *arg)); -char *RCS_getdate PROTO((RCSNode * rcs, const char *date, - int force_tag_match)); -char *RCS_gettag PROTO((RCSNode * rcs, const char *symtag, int force_tag_match, - int *simple_tag)); -int RCS_exist_rev PROTO((RCSNode *rcs, char *rev)); -int RCS_exist_tag PROTO((RCSNode *rcs, char *tag)); -char *RCS_tag2rev PROTO((RCSNode *rcs, char *tag)); -char *RCS_getversion PROTO((RCSNode * rcs, const char *tag, const char *date, - int force_tag_match, int *simple_tag)); -char *RCS_magicrev PROTO((RCSNode *rcs, char *rev)); -int RCS_isbranch PROTO((RCSNode *rcs, const char *rev)); -int RCS_nodeisbranch PROTO((RCSNode *rcs, const char *tag)); -char *RCS_whatbranch PROTO((RCSNode *rcs, const char *tag)); -char *RCS_head PROTO((RCSNode * rcs)); -int RCS_datecmp PROTO((const char *date1, const char *date2)); -time_t RCS_getrevtime PROTO((RCSNode * rcs, const char *rev, char *date, - int fudge)); -List *RCS_symbols PROTO((RCSNode *rcs)); -void RCS_check_tag PROTO((const char *tag)); -int RCS_valid_rev PROTO ((char *rev)); -List *RCS_getlocks PROTO((RCSNode *rcs)); -void freercsnode PROTO((RCSNode ** rnodep)); -char *RCS_getbranch PROTO((RCSNode * rcs, const char *tag, - int force_tag_match)); -char *RCS_branch_head PROTO ((RCSNode *rcs, char *rev)); - -int RCS_isdead PROTO((RCSNode *, const char *)); -char *RCS_getexpand PROTO ((RCSNode *)); -void RCS_setexpand PROTO ((RCSNode *, const char *)); -int RCS_checkout PROTO ((RCSNode *, const char *, const char *, const char *, - const char *, const char *, RCSCHECKOUTPROC, void *)); -int RCS_checkin PROTO ((RCSNode *rcs, const char *workfile, - const char *message, const char *rev, time_t citime, - int flags)); -int RCS_cmp_file PROTO((RCSNode *, const char *, char **, const char *, - const char *, const char *)); -int RCS_settag PROTO ((RCSNode *, const char *, const char *)); -int RCS_deltag PROTO ((RCSNode *, const char *)); -int RCS_setbranch PROTO((RCSNode *, const char *)); -int RCS_lock PROTO ((RCSNode *, const char *, int)); -int RCS_unlock PROTO ((RCSNode *, char *, int)); -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 *)); -void RCS_deltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, const char *, - enum rcs_delta_op, char **, size_t *, - char **, size_t *)); -void RCS_setincexc PROTO ((const char *arg)); -void RCS_setlocalid PROTO ((const char *arg)); -char *make_file_label PROTO ((const char *, const char *, RCSNode *)); - -extern int datesep; -extern int preserve_perms; - -/* From import.c. */ -extern int add_rcs_file PROTO ((const char *, const char *, const char *, - const char *, const char *, const char *, - const char *, int, char **, const char *, - size_t, FILE *)); diff --git a/contrib/cvs/src/rcscmds.c b/contrib/cvs/src/rcscmds.c deleted file mode 100644 index 18182ff..0000000 --- a/contrib/cvs/src/rcscmds.c +++ /dev/null @@ -1,628 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * The functions in this file provide an interface for performing - * operations directly on RCS files. - * - * $FreeBSD$ - */ - -#include "cvs.h" -#include <assert.h> -#include <stdio.h> -#include "diffrun.h" - -/* This file, rcs.h, and rcs.c, together sometimes known as the "RCS - library", are intended to define our interface to RCS files. - - Whether there will also be a version of RCS which uses this - library, or whether the library will be packaged for uses beyond - CVS or RCS (many people would like such a thing) is an open - question. Some considerations: - - 1. An RCS library for CVS must have the capabilities of the - existing CVS code which accesses RCS files. In particular, simple - approaches will often be slow. - - 2. An RCS library should not use code from the current RCS - (5.7 and its ancestors). The code has many problems. Too few - comments, too many layers of abstraction, too many global variables - (the correct number for a library is zero), too much intricately - interwoven functionality, and too many clever hacks. Paul Eggert, - the current RCS maintainer, agrees. - - 3. More work needs to be done in terms of separating out the RCS - library from the rest of CVS (for example, cvs_output should be - replaced by a callback, and the declarations should be centralized - into rcs.h, and probably other such cleanups). - - 4. To be useful for RCS and perhaps for other uses, the library - may need features beyond those needed by CVS. - - 5. Any changes to the RCS file format *must* be compatible. Many, - many tools (not just CVS and RCS) can at least import this format. - RCS and CVS must preserve the current ability to import/export it - (preferably improved--magic branches are currently a roadblock). - See doc/RCSFILES in the CVS distribution for documentation of this - file format. - - On a related note, see the comments at diff_exec, later in this file, - for more on the diff library. */ - -static void RCS_output_diff_options PROTO ((int, char *const *, const char *, - const char *, const char *)); - - -/* Stuff to deal with passing arguments the way libdiff.a wants to deal - with them. This is a crufty interface; there is no good reason for it - to resemble a command line rather than something closer to "struct - log_data" in log.c. */ - -/* First call call_diff_setup to setup any initial arguments. The - argument will be parsed into whitespace separated words and added - to the global call_diff_argv list. - - Then, optionally, call call_diff_add_arg for each additional argument - that you'd like to pass to the diff library. - - Finally, call call_diff or call_diff3 to produce the diffs. */ - -static char **call_diff_argv; -static int call_diff_argc; -static size_t call_diff_argc_allocated; - -static void call_diff_add_arg PROTO ((const char *)); -static void call_diff_setup PROTO ((const char *prog, - int argc, char * const *argv)); -static int call_diff PROTO ((const char *out)); -static int call_diff3 PROTO ((char *out)); - -static void call_diff_write_output PROTO((const char *, size_t)); -static void call_diff_flush_output PROTO((void)); -static void call_diff_write_stdout PROTO((const char *)); -static void call_diff_error PROTO((const char *, const char *, const char *)); - - - -static void -call_diff_add_arg (s) - const char *s; -{ - run_add_arg_p (&call_diff_argc, &call_diff_argc_allocated, &call_diff_argv, - s); -} - - - -/* VARARGS */ -static void -call_diff_setup (prog, argc, argv) - const char *prog; - int argc; - char * const *argv; -{ - int i; - - /* clean out any malloc'ed values from call_diff_argv */ - run_arg_free_p (call_diff_argc, call_diff_argv); - call_diff_argc = 0; - - /* put each word into call_diff_argv, allocating it as we go */ - call_diff_add_arg (prog); - for (i = 0; i < argc; i++) - call_diff_add_arg (argv[i]); -} - - -/* Callback function for the diff library to write data to the output - file. This is used when we are producing output to stdout. */ - -static void -call_diff_write_output (text, len) - const char *text; - size_t len; -{ - if (len > 0) - cvs_output (text, len); -} - -/* Call back function for the diff library to flush the output file. - This is used when we are producing output to stdout. */ - -static void -call_diff_flush_output () -{ - cvs_flushout (); -} - -/* Call back function for the diff library to write to stdout. */ - -static void -call_diff_write_stdout (text) - const char *text; -{ - cvs_output (text, 0); -} - -/* Call back function for the diff library to write to stderr. */ - -static void -call_diff_error (format, a1, a2) - const char *format; - const char *a1; - const char *a2; -{ - /* FIXME: Should we somehow indicate that this error is coming from - the diff library? */ - error (0, 0, format, a1, a2); -} - -/* This set of callback functions is used if we are sending the diff - to stdout. */ - -static struct diff_callbacks call_diff_stdout_callbacks = -{ - call_diff_write_output, - call_diff_flush_output, - call_diff_write_stdout, - call_diff_error -}; - -/* This set of callback functions is used if we are sending the diff - to a file. */ - -static struct diff_callbacks call_diff_file_callbacks = -{ - (void (*) PROTO((const char *, size_t))) NULL, - (void (*) PROTO((void))) NULL, - call_diff_write_stdout, - call_diff_error -}; - - - -static int -call_diff (out) - const char *out; -{ - call_diff_add_arg (NULL); - - if (out == RUN_TTY) - return diff_run (call_diff_argc, call_diff_argv, NULL, - &call_diff_stdout_callbacks); - else - return diff_run (call_diff_argc, call_diff_argv, out, - &call_diff_file_callbacks); -} - - - -static int -call_diff3 (out) - char *out; -{ - if (out == RUN_TTY) - return diff3_run (call_diff_argc, call_diff_argv, NULL, - &call_diff_stdout_callbacks); - else - return diff3_run (call_diff_argc, call_diff_argv, out, - &call_diff_file_callbacks); -} - - - -/* Merge revisions REV1 and REV2. */ - -int -RCS_merge(rcs, path, workfile, options, rev1, rev2) - RCSNode *rcs; - const char *path; - const char *workfile; - const char *options; - const char *rev1; - const char *rev2; -{ - char *xrev1, *xrev2; - char *tmp1, *tmp2; - char *diffout = NULL; - int retval; - - if (options != NULL && options[0] != '\0') - assert (options[0] == '-' && options[1] == 'k'); - - cvs_output ("RCS file: ", 0); - cvs_output (rcs->path, 0); - cvs_output ("\n", 1); - - /* Calculate numeric revision numbers from rev1 and rev2 (may be - symbolic). */ - xrev1 = RCS_gettag (rcs, rev1, 0, NULL); - xrev2 = RCS_gettag (rcs, rev2, 0, NULL); - assert (xrev1 && xrev2); - - /* Check out chosen revisions. The error message when RCS_checkout - fails is not very informative -- it is taken verbatim from RCS 5.7, - and relies on RCS_checkout saying something intelligent upon failure. */ - cvs_output ("retrieving revision ", 0); - cvs_output (xrev1, 0); - cvs_output ("\n", 1); - - tmp1 = cvs_temp_name(); - if (RCS_checkout (rcs, NULL, xrev1, rev1, options, tmp1, - (RCSCHECKOUTPROC)0, NULL)) - { - cvs_outerr ("rcsmerge: co failed\n", 0); - error_exit(); - } - - cvs_output ("retrieving revision ", 0); - cvs_output (xrev2, 0); - cvs_output ("\n", 1); - - tmp2 = cvs_temp_name(); - if (RCS_checkout (rcs, NULL, xrev2, rev2, options, tmp2, - (RCSCHECKOUTPROC)0, NULL)) - { - cvs_outerr ("rcsmerge: co failed\n", 0); - error_exit(); - } - - /* Merge changes. */ - cvs_output ("Merging differences between ", 0); - cvs_output (xrev1, 0); - cvs_output (" and ", 0); - cvs_output (xrev2, 0); - cvs_output (" into ", 0); - cvs_output (workfile, 0); - cvs_output ("\n", 1); - - /* Remember that the first word in the `call_diff_setup' string is used now - only for diagnostic messages -- CVS no longer forks to run diff3. */ - diffout = cvs_temp_name(); - call_diff_setup ("diff3", 0, NULL); - call_diff_add_arg ("-E"); - call_diff_add_arg ("-am"); - - call_diff_add_arg ("-L"); - call_diff_add_arg (workfile); - call_diff_add_arg ("-L"); - call_diff_add_arg (xrev1); - call_diff_add_arg ("-L"); - call_diff_add_arg (xrev2); - - call_diff_add_arg ("--"); - call_diff_add_arg (workfile); - call_diff_add_arg (tmp1); - call_diff_add_arg (tmp2); - - retval = call_diff3 (diffout); - - if (retval == 1) - cvs_outerr ("rcsmerge: warning: conflicts during merge\n", 0); - else if (retval == 2) - error_exit(); - - if (diffout) - copy_file (diffout, workfile); - - /* Clean up. */ - { - int save_noexec = noexec; - noexec = 0; - if (unlink_file (tmp1) < 0) - { - if (!existence_error (errno)) - error (0, errno, "cannot remove temp file %s", tmp1); - } - free (tmp1); - if (unlink_file (tmp2) < 0) - { - if (!existence_error (errno)) - error (0, errno, "cannot remove temp file %s", tmp2); - } - free (tmp2); - if (diffout) - { - if (unlink_file (diffout) < 0) - { - if (!existence_error (errno)) - error (0, errno, "cannot remove temp file %s", diffout); - } - free (diffout); - } - free (xrev1); - free (xrev2); - noexec = save_noexec; - } - - return retval; -} - -/* Diff revisions and/or files. OPTS controls the format of the diff - (it contains options such as "-w -c", &c), or "" for the default. - OPTIONS controls keyword expansion, as a string starting with "-k", - or "" to use the default. REV1 is the first revision to compare - against; it must be non-NULL. If REV2 is non-NULL, compare REV1 - and REV2; if REV2 is NULL compare REV1 with the file in the working - directory, whose name is WORKFILE. LABEL1 and LABEL2 are default - file labels, and (if non-NULL) should be added as -L options - to diff. Output goes to stdout. - - Return value is 0 for success, -1 for a failure which set errno, - or positive for a failure which printed a message on stderr. - - This used to exec rcsdiff, but now calls RCS_checkout and diff_exec. - - An issue is what timezone is used for the dates which appear in the - diff output. rcsdiff uses the -z flag, which is not presently - processed by CVS diff, but I'm not sure exactly how hard to worry - about this--any such features are undocumented in the context of - CVS, and I'm not sure how important to users. */ -int -RCS_exec_rcsdiff (rcsfile, diff_argc, diff_argv, options, rev1, rev1_cache, - rev2, label1, label2, workfile) - RCSNode *rcsfile; - int diff_argc; - char * const *diff_argv; - const char *options; - const char *rev1; - const char *rev1_cache; - const char *rev2; - const char *label1; - const char *label2; - const char *workfile; -{ - char *tmpfile1 = NULL; - char *tmpfile2 = NULL; - const char *use_file1, *use_file2; - int status, retval; - - - cvs_output ("\ -===================================================================\n\ -RCS file: ", 0); - cvs_output (rcsfile->path, 0); - cvs_output ("\n", 1); - - /* Historically, `cvs diff' has expanded the $Name keyword to the - empty string when checking out revisions. This is an accident, - but no one has considered the issue thoroughly enough to determine - what the best behavior is. Passing NULL for the `nametag' argument - preserves the existing behavior. */ - - cvs_output ("retrieving revision ", 0); - cvs_output (rev1, 0); - cvs_output ("\n", 1); - - if (rev1_cache != NULL) - use_file1 = rev1_cache; - else - { - tmpfile1 = cvs_temp_name(); - status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1, - (RCSCHECKOUTPROC)0, NULL); - if (status > 0) - { - retval = status; - goto error_return; - } - else if (status < 0) - { - error( 0, errno, - "cannot check out revision %s of %s", rev1, rcsfile->path ); - retval = 1; - goto error_return; - } - use_file1 = tmpfile1; - } - - if (rev2 == NULL) - { - assert (workfile != NULL); - use_file2 = workfile; - } - else - { - tmpfile2 = cvs_temp_name (); - cvs_output ("retrieving revision ", 0); - cvs_output (rev2, 0); - cvs_output ("\n", 1); - status = RCS_checkout (rcsfile, NULL, rev2, NULL, options, - tmpfile2, (RCSCHECKOUTPROC)0, NULL); - if (status > 0) - { - retval = status; - goto error_return; - } - else if (status < 0) - { - error (0, errno, - "cannot check out revision %s of %s", rev2, rcsfile->path); - return 1; - } - use_file2 = tmpfile2; - } - - RCS_output_diff_options (diff_argc, diff_argv, rev1, rev2, workfile); - status = diff_exec (use_file1, use_file2, label1, label2, - diff_argc, diff_argv, RUN_TTY); - if (status >= 0) - { - retval = status; - goto error_return; - } - else if (status < 0) - { - error (0, errno, - "cannot diff %s and %s", use_file1, use_file2); - retval = 1; - goto error_return; - } - - error_return: - { - /* Call CVS_UNLINK() below rather than unlink_file to avoid the check - * for noexec. - */ - if( tmpfile1 != NULL ) - { - if( CVS_UNLINK( tmpfile1 ) < 0 ) - { - if( !existence_error( errno ) ) - error( 0, errno, "cannot remove temp file %s", tmpfile1 ); - } - free( tmpfile1 ); - } - if( tmpfile2 != NULL ) - { - if( CVS_UNLINK( tmpfile2 ) < 0 ) - { - if( !existence_error( errno ) ) - error( 0, errno, "cannot remove temp file %s", tmpfile2 ); - } - free (tmpfile2); - } - } - - return retval; -} - - - -/* Show differences between two files. This is the start of a diff library. - - Some issues: - - * Should option parsing be part of the library or the caller? The - former allows the library to add options without changing the callers, - but it causes various problems. One is that something like --brief really - wants special handling in CVS, and probably the caller should retain - some flexibility in this area. Another is online help (the library could - have some feature for providing help, but how does that interact with - the help provided by the caller directly?). Another is that as things - stand currently, there is no separate namespace for diff options versus - "cvs diff" options like -l (that is, if the library adds an option which - conflicts with a CVS option, it is trouble). - - * This isn't required for a first-cut diff library, but if there - would be a way for the caller to specify the timestamps that appear - in the diffs (rather than the library getting them from the files), - that would clean up the kludgy utime() calls in patch.c. - - Show differences between FILE1 and FILE2. Either one can be - DEVNULL to indicate a nonexistent file (same as an empty file - currently, I suspect, but that may be an issue in and of itself). - OPTIONS is a list of diff options, or "" if none. At a minimum, - CVS expects that -c (update.c, patch.c) and -n (update.c) will be - supported. Other options, like -u, --speed-large-files, &c, will - be specified if the user specified them. - - OUT is a filename to send the diffs to, or RUN_TTY to send them to - stdout. Error messages go to stderr. Return value is 0 for - success, -1 for a failure which set errno, 1 for success (and some - differences were found), or >1 for a failure which printed a - message on stderr. */ - -int -diff_exec (file1, file2, label1, label2, dargc, dargv, out) - const char *file1; - const char *file2; - const char *label1; - const char *label2; - int dargc; - char * const *dargv; - const char *out; -{ -#ifdef PRESERVE_PERMISSIONS_SUPPORT - /* If either file1 or file2 are special files, pretend they are - /dev/null. Reason: suppose a file that represents a block - special device in one revision becomes a regular file. CVS - must find the `difference' between these files, but a special - file contains no data useful for calculating this metric. The - safe thing to do is to treat the special file as an empty file, - thus recording the regular file's full contents. Doing so will - create extremely large deltas at the point of transition - between device files and regular files, but this is probably - very rare anyway. - - There may be ways around this, but I think they are fraught - with danger. -twp */ - - if (preserve_perms && - strcmp (file1, DEVNULL) != 0 && - strcmp (file2, DEVNULL) != 0) - { - struct stat sb1, sb2; - - if (CVS_LSTAT (file1, &sb1) < 0) - error (1, errno, "cannot get file information for %s", file1); - if (CVS_LSTAT (file2, &sb2) < 0) - error (1, errno, "cannot get file information for %s", file2); - - if (!S_ISREG (sb1.st_mode) && !S_ISDIR (sb1.st_mode)) - file1 = DEVNULL; - if (!S_ISREG (sb2.st_mode) && !S_ISDIR (sb2.st_mode)) - file2 = DEVNULL; - } -#endif - - /* The first arg to call_diff_setup is used only for error reporting. */ - call_diff_setup ("diff", dargc, dargv); - if (label1) - call_diff_add_arg (label1); - if (label2) - call_diff_add_arg (label2); - call_diff_add_arg ("--"); - call_diff_add_arg (file1); - call_diff_add_arg (file2); - - return call_diff (out); -} - -/* Print the options passed to DIFF, in the format used by rcsdiff. - The rcsdiff code that produces this output is extremely hairy, and - it is not clear how rcsdiff decides which options to print and - which not to print. The code below reproduces every rcsdiff run - that I have seen. */ - -static void -RCS_output_diff_options (diff_argc, diff_argv, rev1, rev2, workfile) - int diff_argc; - char * const *diff_argv; - const char *rev1; - const char *rev2; - const char *workfile; -{ - int i; - - cvs_output ("diff", 0); - for (i = 0; i < diff_argc; i++) - { - cvs_output (" ", 1); - cvs_output (diff_argv[i], 0); - } - cvs_output (" -r", 3); - cvs_output (rev1, 0); - - if (rev2) - { - cvs_output (" -r", 3); - cvs_output (rev2, 0); - } - else - { - assert (workfile != NULL); - cvs_output (" ", 1); - cvs_output (workfile, 0); - } - cvs_output ("\n", 1); -} diff --git a/contrib/cvs/src/recurse.c b/contrib/cvs/src/recurse.c deleted file mode 100644 index fb865a9..0000000 --- a/contrib/cvs/src/recurse.c +++ /dev/null @@ -1,1299 +0,0 @@ -/* - * Copyright (C) 1986-2008 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * General recursion handler - * - */ - -#include "cvs.h" -#include "savecwd.h" -#include "fileattr.h" -#include "edit.h" -#include <assert.h> - -static int do_dir_proc PROTO((Node * p, void *closure)); -static int do_file_proc PROTO((Node * p, void *closure)); -static void addlist PROTO((List ** listp, char *key)); -static int unroll_files_proc PROTO((Node *p, void *closure)); -static void addfile PROTO((List **listp, char *dir, char *file)); - -static char *update_dir; -static char *repository = NULL; -static List *filelist = NULL; /* holds list of files on which to operate */ -static List *dirlist = NULL; /* holds list of directories on which to operate */ - -struct recursion_frame { - FILEPROC fileproc; - FILESDONEPROC filesdoneproc; - DIRENTPROC direntproc; - DIRLEAVEPROC dirleaveproc; - void *callerdat; - Dtype flags; - int which; - int aflag; - int locktype; - int dosrcs; - char *repository; /* Keep track of repository for rtag */ -}; - -static int do_recursion PROTO ((struct recursion_frame *frame)); - -/* I am half tempted to shove a struct file_info * into the struct - recursion_frame (but then we would need to modify or create a - recursion_frame for each file), or shove a struct recursion_frame * - into the struct file_info (more tempting, although it isn't completely - clear that the struct file_info should contain info about recursion - processor internals). So instead use this struct. */ - -struct frame_and_file { - struct recursion_frame *frame; - struct file_info *finfo; -}; - -/* Similarly, we need to pass the entries list to do_dir_proc. */ - -struct frame_and_entries { - struct recursion_frame *frame; - List *entries; -}; - - -/* Start a recursive command. - - Command line arguments (ARGC, ARGV) dictate the directories and - files on which we operate. In the special case of no arguments, we - default to ".". */ -int -start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, - argc, argv, local, which, aflag, locktype, - update_preload, dosrcs, repository_in) - FILEPROC fileproc; - FILESDONEPROC filesdoneproc; - DIRENTPROC direntproc; - DIRLEAVEPROC dirleaveproc; - void *callerdat; - - int argc; - char **argv; - int local; - - /* This specifies the kind of recursion. There are several cases: - - 1. W_LOCAL is not set but W_REPOS or W_ATTIC is. The current - directory when we are called must be the repository and - recursion proceeds according to what exists in the repository. - - 2a. W_LOCAL is set but W_REPOS and W_ATTIC are not. The - current directory when we are called must be the working - directory. Recursion proceeds according to what exists in the - working directory, never (I think) consulting any part of the - repository which does not correspond to the working directory - ("correspond" == Name_Repository). - - 2b. W_LOCAL is set and so is W_REPOS or W_ATTIC. This is the - weird one. The current directory when we are called must be - the working directory. We recurse through working directories, - but we recurse into a directory if it is exists in the working - directory *or* it exists in the repository. If a directory - does not exist in the working directory, the direntproc must - either tell us to skip it (R_SKIP_ALL), or must create it (I - think those are the only two cases). */ - int which; - - int aflag; - int locktype; - char *update_preload; - int dosrcs; - /* Keep track of the repository string. This is only for the remote mode, - * specifically, r* commands (rtag, rdiff, co, ...) where xgetwd() was - * used to locate the repository. Things would break when xgetwd() was - * used with a symlinked repository because xgetwd() would return the true - * path and in some cases this would cause the path to be printed as other - * than the user specified in error messages and in other cases some of - * CVS's security assertions would fail. - */ - char *repository_in; -{ - int i, err = 0; -#ifdef CLIENT_SUPPORT - List *args_to_send_when_finished = NULL; -#endif - List *files_by_dir = NULL; - struct recursion_frame frame; - - frame.fileproc = fileproc; - frame.filesdoneproc = filesdoneproc; - frame.direntproc = direntproc; - frame.dirleaveproc = dirleaveproc; - frame.callerdat = callerdat; - frame.flags = local ? R_SKIP_DIRS : R_PROCESS; - frame.which = which; - frame.aflag = aflag; - frame.locktype = locktype; - frame.dosrcs = dosrcs; - - /* If our repository_in has a trailing "/.", remove it before storing it - * for do_recursion(). - * - * FIXME: This is somewhat of a hack in the sense that many of our callers - * painstakingly compute and add the trailing '.' we now remove. - */ - while (repository_in && strlen (repository_in) >= 2 - && repository_in[strlen (repository_in) - 2] == '/' - && repository_in[strlen (repository_in) - 1] == '.') - { - /* Beware the case where the string is exactly "/." or "//.". - * Paths with a leading "//" are special on some early UNIXes. - */ - if (strlen (repository_in) == 2 || strlen (repository_in) == 3) - repository_in[strlen (repository_in) - 1] = '\0'; - else - repository_in[strlen (repository_in) - 2] = '\0'; - } - frame.repository = repository_in; - - expand_wild (argc, argv, &argc, &argv); - - if (update_preload == NULL) - update_dir = xstrdup (""); - else - update_dir = xstrdup (update_preload); - - /* clean up from any previous calls to start_recursion */ - if (repository) - { - free (repository); - repository = (char *) NULL; - } - if (filelist) - dellist (&filelist); /* FIXME-krp: no longer correct. */ - if (dirlist) - dellist (&dirlist); - -#ifdef SERVER_SUPPORT - if (server_active) - { - for (i = 0; i < argc; ++i) - server_pathname_check (argv[i]); - } -#endif - - if (argc == 0) - { - int just_subdirs = (which & W_LOCAL) && !isdir (CVSADM); - -#ifdef CLIENT_SUPPORT - if (!just_subdirs - && CVSroot_cmdline == NULL - && current_parsed_root->isremote) - { - cvsroot_t *root = Name_Root (NULL, update_dir); - if (root) - { - if (strcmp (root->original, current_parsed_root->original)) - /* We're skipping this directory because it is for - * a different root. Therefore, we just want to - * do the subdirectories only. Processing files would - * cause a working directory from one repository to be - * processed against a different repository, which could - * cause all kinds of spurious conflicts and such. - * - * Question: what about the case of "cvs update foo" - * where we process foo/bar and not foo itself? That - * seems to be handled somewhere (else) but why should - * it be a separate case? Needs investigation... */ - just_subdirs = 1; - free_cvsroot_t (root); - } - } -#endif - - /* - * There were no arguments, so we'll probably just recurse. The - * exception to the rule is when we are called from a directory - * without any CVS administration files. That has always meant to - * process each of the sub-directories, so we pretend like we were - * called with the list of sub-dirs of the current dir as args - */ - if (just_subdirs) - { - dirlist = Find_Directories ((char *) NULL, W_LOCAL, (List *) NULL); - /* If there are no sub-directories, there is a certain logic in - favor of doing nothing, but in fact probably the user is just - confused about what directory they are in, or whether they - cvs add'd a new directory. In the case of at least one - sub-directory, at least when we recurse into them we - notice (hopefully) whether they are under CVS control. */ - if (list_isempty (dirlist)) - { - if (update_dir[0] == '\0') - error (0, 0, "in directory .:"); - else - error (0, 0, "in directory %s:", update_dir); - error (1, 0, - "there is no version here; run '%s checkout' first", - program_name); - } -#ifdef CLIENT_SUPPORT - else if (current_parsed_root->isremote && server_started) - { - /* In the the case "cvs update foo bar baz", a call to - send_file_names in update.c will have sent the - appropriate "Argument" commands to the server. In - this case, that won't have happened, so we need to - do it here. While this example uses "update", this - generalizes to other commands. */ - - /* This is the same call to Find_Directories as above. - FIXME: perhaps it would be better to write a - function that duplicates a list. */ - args_to_send_when_finished = Find_Directories ((char *) NULL, - W_LOCAL, - (List *) NULL); - } -#endif - } - else - addlist (&dirlist, "."); - - goto do_the_work; - } - - - /* - * There were arguments, so we have to handle them by hand. To do - * that, we set up the filelist and dirlist with the arguments and - * call do_recursion. do_recursion recognizes the fact that the - * lists are non-null when it starts and doesn't update them. - * - * explicitly named directories are stored in dirlist. - * explicitly named files are stored in filelist. - * other possibility is named entities whicha are not currently in - * the working directory. - */ - - for (i = 0; i < argc; i++) - { - /* if this argument is a directory, then add it to the list of - directories. */ - - if (!wrap_name_has (argv[i], WRAP_TOCVS) && isdir (argv[i])) - { - strip_trailing_slashes (argv[i]); - addlist (&dirlist, argv[i]); - } - else - { - /* otherwise, split argument into directory and component names. */ - char *dir; - char *comp; - char *file_to_try; - - /* Now break out argv[i] into directory part (DIR) and file part (COMP). - DIR and COMP will each point to a newly malloc'd string. */ - dir = xstrdup (argv[i]); - /* Its okay to discard the const below - we know we just allocated - * dir ourselves. - */ - comp = (char *)last_component (dir); - if (comp == dir) - { - /* no dir component. What we have is an implied "./" */ - dir = xstrdup("."); - } - else - { - char *p = comp; - - p[-1] = '\0'; - comp = xstrdup (p); - } - - /* if this argument exists as a file in the current - working directory tree, then add it to the files list. */ - - if (!(which & W_LOCAL)) - { - /* If doing rtag, we've done a chdir to the repository. */ - file_to_try = xmalloc (strlen (argv[i]) + sizeof (RCSEXT) + 5); - sprintf (file_to_try, "%s%s", argv[i], RCSEXT); - } - else - file_to_try = xstrdup (argv[i]); - - if (isfile (file_to_try)) - addfile (&files_by_dir, dir, comp); - else if (isdir (dir)) - { - if ((which & W_LOCAL) && isdir (CVSADM) && - !current_parsed_root->isremote) - { - /* otherwise, look for it in the repository. */ - char *tmp_update_dir; - char *repos; - char *reposfile; - - tmp_update_dir = xmalloc (strlen (update_dir) - + strlen (dir) - + 5); - strcpy (tmp_update_dir, update_dir); - - if (*tmp_update_dir != '\0') - (void) strcat (tmp_update_dir, "/"); - - (void) strcat (tmp_update_dir, dir); - - /* look for it in the repository. */ - repos = Name_Repository (dir, tmp_update_dir); - reposfile = xmalloc (strlen (repos) - + strlen (comp) - + 5); - (void) sprintf (reposfile, "%s/%s", repos, comp); - free (repos); - - if (!wrap_name_has (comp, WRAP_TOCVS) && isdir (reposfile)) - addlist (&dirlist, argv[i]); - else - addfile (&files_by_dir, dir, comp); - - free (tmp_update_dir); - free (reposfile); - } - else - addfile (&files_by_dir, dir, comp); - } - else - error (1, 0, "no such directory `%s'", dir); - - free (file_to_try); - free (dir); - free (comp); - } - } - - /* At this point we have looped over all named arguments and built - a coupla lists. Now we unroll the lists, setting up and - calling do_recursion. */ - - err += walklist (files_by_dir, unroll_files_proc, (void *) &frame); - dellist(&files_by_dir); - - /* then do_recursion on the dirlist. */ - if (dirlist != NULL) - { - do_the_work: - err += do_recursion (&frame); - } - - /* Free the data which expand_wild allocated. */ - free_names (&argc, argv); - - free (update_dir); - update_dir = NULL; - -#ifdef CLIENT_SUPPORT - if (args_to_send_when_finished != NULL) - { - /* FIXME (njc): in the multiroot case, we don't want to send - argument commands for those top-level directories which do - not contain any subdirectories which have files checked out - from current_parsed_root->original. If we do, and two repositories - have a module with the same name, nasty things could happen. - - This is hard. Perhaps we should send the Argument commands - later in this procedure, after we've had a chance to notice - which directores we're using (after do_recursion has been - called once). This means a _lot_ of rewriting, however. - - What we need to do for that to happen is descend the tree - and construct a list of directories which are checked out - from current_cvsroot. Now, we eliminate from the list all - of those directories which are immediate subdirectories of - another directory in the list. To say that the opposite - way, we keep the directories which are not immediate - subdirectories of any other in the list. Here's a picture: - - a - / \ - B C - / \ - D e - / \ - F G - / \ - H I - - The node in capitals are those directories which are - checked out from current_cvsroot. We want the list to - contain B, C, F, and G. D, H, and I are not included, - because their parents are also checked out from - current_cvsroot. - - The algorithm should be: - - 1) construct a tree of all directory names where each - element contains a directory name and a flag which notes if - that directory is checked out from current_cvsroot - - a0 - / \ - B1 C1 - / \ - D1 e0 - / \ - F1 G1 - / \ - H1 I1 - - 2) Recursively descend the tree. For each node, recurse - before processing the node. If the flag is zero, do - nothing. If the flag is 1, check the node's parent. If - the parent's flag is one, change the current entry's flag - to zero. - - a0 - / \ - B1 C1 - / \ - D0 e0 - / \ - F1 G1 - / \ - H0 I0 - - 3) Walk the tree and spit out "Argument" commands to tell - the server which directories to munge. - - Yuck. It's not clear this is worth spending time on, since - we might want to disable cvs commands entirely from - directories that do not have CVSADM files... - - Anyways, the solution as it stands has modified server.c - (dirswitch) to create admin files [via server.c - (create_adm_p)] in all path elements for a client's - "Directory xxx" command, which forces the server to descend - and serve the files there. client.c (send_file_names) has - also been modified to send only those arguments which are - appropriate to current_parsed_root->original. - - */ - - /* Construct a fake argc/argv pair. */ - - int our_argc = 0, i; - char **our_argv = NULL; - - if (! list_isempty (args_to_send_when_finished)) - { - Node *head, *p; - - head = args_to_send_when_finished->list; - - /* count the number of nodes */ - i = 0; - for (p = head->next; p != head; p = p->next) - i++; - our_argc = i; - - /* create the argument vector */ - our_argv = (char **) xmalloc (sizeof (char *) * our_argc); - - /* populate it */ - i = 0; - for (p = head->next; p != head; p = p->next) - our_argv[i++] = xstrdup (p->key); - } - - /* We don't want to expand widcards, since we've just created - a list of directories directly from the filesystem. */ - send_file_names (our_argc, our_argv, 0); - - /* Free our argc/argv. */ - if (our_argv != NULL) - { - for (i = 0; i < our_argc; i++) - free (our_argv[i]); - free (our_argv); - } - - dellist (&args_to_send_when_finished); - } -#endif - - return (err); -} - -/* - * Implement the recursive policies on the local directory. This may be - * called directly, or may be called by start_recursion - */ -static int -do_recursion (frame) - struct recursion_frame *frame; -{ - int err = 0; - int dodoneproc = 1; - char *srepository = NULL; - List *entries = NULL; - int locktype; - int process_this_directory = 1; - - /* do nothing if told */ - if (frame->flags == R_SKIP_ALL) - return (0); - - locktype = noexec ? CVS_LOCK_NONE : frame->locktype; - - /* The fact that locks are not active here is what makes us fail to have - the - - If someone commits some changes in one cvs command, - then an update by someone else will either get all the - changes, or none of them. - - property (see node Concurrency in cvs.texinfo). - - The most straightforward fix would just to readlock the whole - tree before starting an update, but that means that if a commit - gets blocked on a big update, it might need to wait a *long* - time. - - A more adequate fix would be a two-pass design for update, - checkout, etc. The first pass would go through the repository, - with the whole tree readlocked, noting what versions of each - file we want to get. The second pass would release all locks - (except perhaps short-term locks on one file at a - time--although I think RCS already deals with this) and - actually get the files, specifying the particular versions it wants. - - This could be sped up by separating out the data needed for the - first pass into a separate file(s)--for example a file - attribute for each file whose value contains the head revision - for each branch. The structure should be designed so that - commit can relatively quickly update the information for a - single file or a handful of files (file attributes, as - implemented in Jan 96, are probably acceptable; improvements - would be possible such as branch attributes which are in - separate files for each branch). */ - -#if defined(SERVER_SUPPORT) && defined(SERVER_FLOWCONTROL) - /* - * Now would be a good time to check to see if we need to stop - * generating data, to give the buffers a chance to drain to the - * remote client. We should not have locks active at this point, - * but if there are writelocks around, we cannot pause here. */ - if (server_active && locktype != CVS_LOCK_WRITE) - server_pause_check(); -#endif - - /* Check the value in CVSADM_ROOT and see if it's in the list. If - not, add it to our lists of CVS/Root directories and do not - process the files in this directory. Otherwise, continue as - usual. THIS_ROOT might be NULL if we're doing an initial - checkout -- check before using it. The default should be that - we process a directory's contents and only skip those contents - if a CVS/Root file exists. - - If we're running the server, we want to process all - directories, since we're guaranteed to have only one CVSROOT -- - our own. */ - - /* If -d was specified, it should override CVS/Root. - - In the single-repository case, it is long-standing CVS behavior - and makes sense - the user might want another access method, - another server (which mounts the same repository), &c. - - In the multiple-repository case, -d overrides all CVS/Root - files. That is the only plausible generalization I can - think of. */ - if (CVSroot_cmdline == NULL && !server_active) - { - cvsroot_t *this_root = Name_Root ((char *) NULL, update_dir); - if (this_root != NULL) - { - if (findnode (root_directories, this_root->original)) - { - process_this_directory = !strcmp (current_parsed_root->original, - this_root->original); - free_cvsroot_t (this_root); - } - else - { - /* Add it to our list. */ - - Node *n = getnode (); - n->type = NT_UNKNOWN; - n->key = xstrdup (this_root->original); - n->data = this_root; - - if (addnode (root_directories, n)) - error (1, 0, "cannot add new CVSROOT %s", - this_root->original); - - process_this_directory = 0; - } - } - } - - /* - * Fill in repository with the current repository - */ - if (frame->which & W_LOCAL) - { - if (isdir (CVSADM)) - { - repository = Name_Repository ((char *) NULL, update_dir); - srepository = repository; /* remember what to free */ - } - else - repository = NULL; - } - else - { - repository = frame->repository; - assert (repository != NULL); - } - - fileattr_startdir (repository); - - /* - * The filesdoneproc needs to be called for each directory where files - * processed, or each directory that is processed by a call where no - * directories were passed in. In fact, the only time we don't want to - * call back the filesdoneproc is when we are processing directories that - * were passed in on the command line (or in the special case of `.' when - * we were called with no args - */ - if (dirlist != NULL && filelist == NULL) - dodoneproc = 0; - - /* - * If filelist or dirlist is already set, we don't look again. Otherwise, - * find the files and directories - */ - if (filelist == NULL && dirlist == NULL) - { - /* both lists were NULL, so start from scratch */ - if (frame->fileproc != NULL && frame->flags != R_SKIP_FILES) - { - int lwhich = frame->which; - - /* be sure to look in the attic if we have sticky tags/date */ - if ((lwhich & W_ATTIC) == 0) - if (isreadable (CVSADM_TAG)) - lwhich |= W_ATTIC; - - /* In the !(which & W_LOCAL) case, we filled in repository - earlier in the function. In the (which & W_LOCAL) case, - the Find_Names function is going to look through the - Entries file. If we do not have a repository, that - does not make sense, so we insist upon having a - repository at this point. Name_Repository will give a - reasonable error message. */ - if (repository == NULL) - { - Name_Repository ((char *) NULL, update_dir); - assert (!"Not reached. Please report this problem to <" - PACKAGE_BUGREPORT ">"); - } - - /* find the files and fill in entries if appropriate */ - if (process_this_directory) - { - filelist = Find_Names (repository, lwhich, frame->aflag, - &entries); - if (filelist == NULL) - { - error (0, 0, "skipping directory %s", update_dir); - /* Note that Find_Directories and the filesdoneproc - in particular would do bad things ("? foo.c" in - the case of some filesdoneproc's). */ - goto skip_directory; - } - } - } - - /* find sub-directories if we will recurse */ - if (frame->flags != R_SKIP_DIRS) - dirlist = Find_Directories ( - process_this_directory ? repository : NULL, - frame->which, entries); - } - else - { - /* something was passed on the command line */ - if (filelist != NULL && frame->fileproc != NULL) - { - /* we will process files, so pre-parse entries */ - if (frame->which & W_LOCAL) - entries = Entries_Open (frame->aflag, NULL); - } - } - - /* process the files (if any) */ - if (process_this_directory && filelist != NULL && frame->fileproc) - { - struct file_info finfo_struct; - struct frame_and_file frfile; - - /* read lock it if necessary */ - if (repository) - { - if (locktype == CVS_LOCK_READ) - { - if (Reader_Lock (repository) != 0) - error (1, 0, "read lock failed - giving up"); - } - else if (locktype == CVS_LOCK_WRITE) - lock_dir_for_write (repository); - } - -#ifdef CLIENT_SUPPORT - /* For the server, we handle notifications in a completely different - place (server_notify). For local, we can't do them here--we don't - have writelocks in place, and there is no way to get writelocks - here. */ - if (current_parsed_root->isremote) - cvs_notify_check (repository, update_dir); -#endif /* CLIENT_SUPPORT */ - - finfo_struct.repository = repository; - finfo_struct.update_dir = update_dir; - finfo_struct.entries = entries; - /* do_file_proc will fill in finfo_struct.file. */ - - frfile.finfo = &finfo_struct; - frfile.frame = frame; - - /* process the files */ - err += walklist (filelist, do_file_proc, &frfile); - - /* unlock it */ - if (/* We only lock the repository above when repository is set */ - repository - /* and when asked for a read or write lock. */ - && locktype != CVS_LOCK_NONE) - Lock_Cleanup (); - - /* clean up */ - dellist (&filelist); - } - - /* call-back files done proc (if any) */ - if (process_this_directory && dodoneproc && frame->filesdoneproc != NULL) - err = frame->filesdoneproc (frame->callerdat, err, repository, - update_dir[0] ? update_dir : ".", - entries); - - skip_directory: - fileattr_write (); - fileattr_free (); - - /* process the directories (if necessary) */ - if (dirlist != NULL) - { - struct frame_and_entries frent; - - frent.frame = frame; - frent.entries = entries; - err += walklist (dirlist, do_dir_proc, (void *) &frent); - } -#if 0 - else if (frame->dirleaveproc != NULL) - err += frame->dirleaveproc (frame->callerdat, ".", err, "."); -#endif - dellist (&dirlist); - - if (entries) - { - Entries_Close (entries); - entries = NULL; - } - - /* free the saved copy of the pointer if necessary */ - if (srepository) - { - free (srepository); - } - repository = (char *) NULL; - - return err; -} - - - -/* - * Process each of the files in the list with the callback proc - */ -static int -do_file_proc (p, closure) - Node *p; - void *closure; -{ - struct frame_and_file *frfile = (struct frame_and_file *)closure; - struct file_info *finfo = frfile->finfo; - int ret; - char *tmp; - - finfo->file = p->key; - tmp = xmalloc (strlen (finfo->file) - + strlen (finfo->update_dir) - + 2); - tmp[0] = '\0'; - if (finfo->update_dir[0] != '\0') - { - strcat (tmp, finfo->update_dir); - strcat (tmp, "/"); - } - strcat (tmp, finfo->file); - - if (frfile->frame->dosrcs && repository) - { - finfo->rcs = RCS_parse (finfo->file, repository); - - /* OK, without W_LOCAL the error handling becomes relatively - simple. The file names came from readdir() on the - repository and so we know any ENOENT is an error - (e.g. symlink pointing to nothing). Now, the logic could - be simpler - since we got the name from readdir, we could - just be calling RCS_parsercsfile. */ - if (finfo->rcs == NULL - && !(frfile->frame->which & W_LOCAL)) - { - error (0, 0, "could not read RCS file for %s", tmp); - free (tmp); - cvs_flushout (); - return 0; - } - } - else - finfo->rcs = (RCSNode *) NULL; - finfo->fullname = tmp; - ret = frfile->frame->fileproc (frfile->frame->callerdat, finfo); - - freercsnode(&finfo->rcs); - free (tmp); - - /* Allow the user to monitor progress with tail -f. Doing this once - per file should be no big deal, but we don't want the performance - hit of flushing on every line like previous versions of CVS. */ - cvs_flushout (); - - return ret; -} - - - -/* - * Process each of the directories in the list (recursing as we go) - */ -static int -do_dir_proc (p, closure) - Node *p; - void *closure; -{ - struct frame_and_entries *frent = (struct frame_and_entries *) closure; - struct recursion_frame *frame = frent->frame; - struct recursion_frame xframe; - char *dir = p->key; - char *newrepos; - List *sdirlist; - char *srepository; - Dtype dir_return = R_PROCESS; - int stripped_dot = 0; - int err = 0; - struct saved_cwd cwd; - char *saved_update_dir; - int process_this_directory = 1; - - if (fncmp (dir, CVSADM) == 0) - { - /* This seems to most often happen when users (beginning users, - generally), try "cvs ci *" or something similar. On that - theory, it is possible that we should just silently skip the - CVSADM directories, but on the other hand, using a wildcard - like this isn't necessarily a practice to encourage (it operates - only on files which exist in the working directory, unlike - regular CVS recursion). */ - - /* FIXME-reentrancy: printed_cvs_msg should be in a "command - struct" or some such, so that it gets cleared for each new - command (this is possible using the remote protocol and a - custom-written client). The struct recursion_frame is not - far back enough though, some commands (commit at least) - will call start_recursion several times. An alternate solution - would be to take this whole check and move it to a new function - validate_arguments or some such that all the commands call - and which snips the offending directory from the argc,argv - vector. */ - static int printed_cvs_msg = 0; - if (!printed_cvs_msg) - { - error (0, 0, "warning: directory %s specified in argument", - dir); - error (0, 0, "\ -but CVS uses %s for its own purposes; skipping %s directory", - CVSADM, dir); - printed_cvs_msg = 1; - } - return 0; - } - - saved_update_dir = update_dir; - update_dir = xmalloc (strlen (saved_update_dir) - + strlen (dir) - + 5); - strcpy (update_dir, saved_update_dir); - - /* set up update_dir - skip dots if not at start */ - if (strcmp (dir, ".") != 0) - { - if (update_dir[0] != '\0') - { - (void) strcat (update_dir, "/"); - (void) strcat (update_dir, dir); - } - else - (void) strcpy (update_dir, dir); - - /* - * Here we need a plausible repository name for the sub-directory. We - * create one by concatenating the new directory name onto the - * previous repository name. The only case where the name should be - * used is in the case where we are creating a new sub-directory for - * update -d and in that case the generated name will be correct. - */ - if (repository == NULL) - newrepos = xstrdup (""); - else - { - newrepos = xmalloc (strlen (repository) + strlen (dir) + 5); - sprintf (newrepos, "%s/%s", repository, dir); - } - } - else - { - if (update_dir[0] == '\0') - (void) strcpy (update_dir, dir); - - if (repository == NULL) - newrepos = xstrdup (""); - else - newrepos = xstrdup (repository); - } - - /* Check to see that the CVSADM directory, if it exists, seems to be - well-formed. It can be missing files if the user hit ^C in the - middle of a previous run. We want to (a) make this a nonfatal - error, and (b) make sure we print which directory has the - problem. - - Do this before the direntproc, so that (1) the direntproc - doesn't have to guess/deduce whether we will skip the directory - (e.g. send_dirent_proc and whether to send the directory), and - (2) so that the warm fuzzy doesn't get printed if we skip the - directory. */ - if (frame->which & W_LOCAL) - { - char *cvsadmdir; - - cvsadmdir = xmalloc (strlen (dir) - + sizeof (CVSADM_REP) - + sizeof (CVSADM_ENT) - + 80); - - strcpy (cvsadmdir, dir); - strcat (cvsadmdir, "/"); - strcat (cvsadmdir, CVSADM); - if (isdir (cvsadmdir)) - { - strcpy (cvsadmdir, dir); - strcat (cvsadmdir, "/"); - strcat (cvsadmdir, CVSADM_REP); - if (!isfile (cvsadmdir)) - { - /* Some commands like update may have printed "? foo" but - if we were planning to recurse, and don't on account of - CVS/Repository, we want to say why. */ - error (0, 0, "ignoring %s (%s missing)", update_dir, - CVSADM_REP); - dir_return = R_SKIP_ALL; - } - - /* Likewise for CVS/Entries. */ - if (dir_return != R_SKIP_ALL) - { - strcpy (cvsadmdir, dir); - strcat (cvsadmdir, "/"); - strcat (cvsadmdir, CVSADM_ENT); - if (!isfile (cvsadmdir)) - { - /* Some commands like update may have printed "? foo" but - if we were planning to recurse, and don't on account of - CVS/Repository, we want to say why. */ - error (0, 0, "ignoring %s (%s missing)", update_dir, - CVSADM_ENT); - dir_return = R_SKIP_ALL; - } - } - } - free (cvsadmdir); - } - - /* Only process this directory if the root matches. This nearly - duplicates code in do_recursion. */ - - /* If -d was specified, it should override CVS/Root. - - In the single-repository case, it is long-standing CVS behavior - and makes sense - the user might want another access method, - another server (which mounts the same repository), &c. - - In the multiple-repository case, -d overrides all CVS/Root - files. That is the only plausible generalization I can - think of. */ - if (CVSroot_cmdline == NULL && !server_active) - { - cvsroot_t *this_root = Name_Root (dir, update_dir); - if (this_root != NULL) - { - if (findnode (root_directories, this_root->original)) - { - process_this_directory = !strcmp (current_parsed_root->original, - this_root->original); - free_cvsroot_t (this_root); - } - else - { - /* Add it to our list. */ - - Node *n = getnode (); - n->type = NT_UNKNOWN; - n->key = xstrdup (this_root->original); - n->data = this_root; - - if (addnode (root_directories, n)) - error (1, 0, "cannot add new CVSROOT %s", - this_root->original); - - process_this_directory = 0; - } - } - } - - /* call-back dir entry proc (if any) */ - if (dir_return == R_SKIP_ALL) - ; - else if (frame->direntproc != NULL) - { - /* If we're doing the actual processing, call direntproc. - Otherwise, assume that we need to process this directory - and recurse. FIXME. */ - - if (process_this_directory) - dir_return = frame->direntproc (frame->callerdat, dir, newrepos, - update_dir, frent->entries); - else - dir_return = R_PROCESS; - } - else - { - /* Generic behavior. I don't see a reason to make the caller specify - a direntproc just to get this. */ - if ((frame->which & W_LOCAL) && !isdir (dir)) - dir_return = R_SKIP_ALL; - } - - free (newrepos); - - /* only process the dir if the return code was 0 */ - if (dir_return != R_SKIP_ALL) - { - /* save our current directory and static vars */ - if (save_cwd (&cwd)) - error_exit (); - sdirlist = dirlist; - srepository = repository; - dirlist = NULL; - - /* cd to the sub-directory */ - if (CVS_CHDIR (dir) < 0) - error (1, errno, "could not chdir to %s", dir); - - /* honor the global SKIP_DIRS (a.k.a. local) */ - if (frame->flags == R_SKIP_DIRS) - dir_return = R_SKIP_DIRS; - - /* remember if the `.' will be stripped for subsequent dirs */ - if (strcmp (update_dir, ".") == 0) - { - update_dir[0] = '\0'; - stripped_dot = 1; - } - - /* make the recursive call */ - xframe = *frame; - xframe.flags = dir_return; - /* Keep track of repository, really just for r* commands (rtag, rdiff, - * co, ...) to tag_check_valid, since all the other commands use - * CVS/Repository to figure it out per directory. - */ - if (repository) - { - if (strcmp (dir, ".") == 0) - xframe.repository = xstrdup (repository); - else - { - xframe.repository = xmalloc (strlen (repository) - + strlen (dir) - + 2); - sprintf (xframe.repository, "%s/%s", repository, dir); - } - } - else - xframe.repository = NULL; - err += do_recursion (&xframe); - if (xframe.repository) - { - free (xframe.repository); - xframe.repository = NULL; - } - - /* put the `.' back if necessary */ - if (stripped_dot) - (void) strcpy (update_dir, "."); - - /* call-back dir leave proc (if any) */ - if (process_this_directory && frame->dirleaveproc != NULL) - err = frame->dirleaveproc (frame->callerdat, dir, err, update_dir, - frent->entries); - - /* get back to where we started and restore state vars */ - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - dirlist = sdirlist; - repository = srepository; - } - - free (update_dir); - update_dir = saved_update_dir; - - return err; -} - -/* - * Add a node to a list allocating the list if necessary. - */ -static void -addlist (listp, key) - List **listp; - char *key; -{ - Node *p; - - if (*listp == NULL) - *listp = getlist (); - p = getnode (); - p->type = FILES; - p->key = xstrdup (key); - if (addnode (*listp, p) != 0) - freenode (p); -} - -static void -addfile (listp, dir, file) - List **listp; - char *dir; - char *file; -{ - Node *n; - List *fl; - - /* add this dir. */ - addlist (listp, dir); - - n = findnode (*listp, dir); - if (n == NULL) - { - error (1, 0, "can't find recently added dir node `%s' in start_recursion.", - dir); - } - - n->type = DIRS; - fl = n->data; - addlist (&fl, file); - n->data = fl; - return; -} - -static int -unroll_files_proc (p, closure) - Node *p; - void *closure; -{ - Node *n; - struct recursion_frame *frame = (struct recursion_frame *) closure; - int err = 0; - List *save_dirlist; - char *save_update_dir = NULL; - struct saved_cwd cwd; - - /* if this dir was also an explicitly named argument, then skip - it. We'll catch it later when we do dirs. */ - n = findnode (dirlist, p->key); - if (n != NULL) - return (0); - - /* otherwise, call dorecusion for this list of files. */ - filelist = p->data; - p->data = NULL; - save_dirlist = dirlist; - dirlist = NULL; - - if (strcmp(p->key, ".") != 0) - { - if (save_cwd (&cwd)) - error_exit (); - if ( CVS_CHDIR (p->key) < 0) - error (1, errno, "could not chdir to %s", p->key); - - save_update_dir = update_dir; - update_dir = xmalloc (strlen (save_update_dir) - + strlen (p->key) - + 5); - strcpy (update_dir, save_update_dir); - - if (*update_dir != '\0') - (void) strcat (update_dir, "/"); - - (void) strcat (update_dir, p->key); - } - - err += do_recursion (frame); - - if (save_update_dir != NULL) - { - free (update_dir); - update_dir = save_update_dir; - - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - } - - dirlist = save_dirlist; - if (filelist) - dellist (&filelist); - return(err); -} diff --git a/contrib/cvs/src/release.c b/contrib/cvs/src/release.c deleted file mode 100644 index 27a16c0..0000000 --- a/contrib/cvs/src/release.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (C) 1994-2005 The Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* - * Release: "cancel" a checkout in the history log. - * - * - Enter a line in the history log indicating the "release". - If asked to, - * delete the local working directory. - */ - -#include "cvs.h" -#include "savecwd.h" -#include "getline.h" - -static const char *const release_usage[] = -{ - "Usage: %s %s [-d] directories...\n", - "\t-d\tDelete the given directory.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -#ifdef SERVER_SUPPORT -static int release_server PROTO ((int argc, char **argv)); - -/* This is the server side of cvs release. */ -static int -release_server (argc, argv) - int argc; - char **argv; -{ - int i; - - /* Note that we skip argv[0]. */ - for (i = 1; i < argc; ++i) - history_write ('F', argv[i], "", argv[i], ""); - return 0; -} - -#endif /* SERVER_SUPPORT */ - -/* There are various things to improve about this implementation: - - 1. Using run_popen to run "cvs update" could be replaced by a - fairly simple start_recursion/classify_file loop--a win for - portability, performance, and cleanliness. In particular, there is - no particularly good way to find the right "cvs". - - 2. The fact that "cvs update" contacts the server slows things down; - it undermines the case for using "cvs release" rather than "rm -rf". - However, for correctly printing "? foo" and correctly handling - CVSROOTADM_IGNORE, we currently need to contact the server. (One - idea for how to fix this is to stash a copy of CVSROOTADM_IGNORE in - the working directories; see comment at base_* in entries.c for a - few thoughts on that). - - 3. Would be nice to take processing things on the client side one step - further, and making it like edit/unedit in terms of working well if - disconnected from the network, and then sending a delayed - notification. - - 4. Having separate network turnarounds for the "Notify" request - which we do as part of unedit, and for the "release" itself, is slow - and unnecessary. */ - -int -release (argc, argv) - int argc; - char **argv; -{ - FILE *fp; - int i, c; - char *line = NULL; - size_t line_allocated = 0; - char *update_cmd; - char *thisarg; - int arg_start_idx; - int err = 0; - short delete_flag = 0; - struct saved_cwd cwd; - -#ifdef SERVER_SUPPORT - if (server_active) - return release_server (argc, argv); -#endif - - /* Everything from here on is client or local. */ - if (argc == -1) - usage (release_usage); - optind = 0; - while ((c = getopt (argc, argv, "+Qdq")) != -1) - { - switch (c) - { - case 'Q': - case 'q': - error (1, 0, - "-q or -Q must be specified before \"%s\"", - cvs_cmd_name); - break; - case 'd': - delete_flag++; - break; - case '?': - default: - usage (release_usage); - break; - } - } - argc -= optind; - argv += optind; - - /* We're going to run "cvs -n -q update" and check its output; if - * the output is sufficiently unalarming, then we release with no - * questions asked. Else we prompt, then maybe release. - * (Well, actually we ask no matter what. Our notion of "sufficiently - * unalarming" doesn't take into account "? foo.c" files, so it is - * up to the user to take note of them, at least currently - * (ignore-193 in testsuite)). - */ - /* Construct the update command. Be sure to add authentication and - encryption if we are using them currently, else our child process may - not be able to communicate with the server. */ - update_cmd = xmalloc (strlen (program_path) - + strlen (current_parsed_root->original) - + 1 + 3 + 3 + 16 + 1); - sprintf (update_cmd, "%s %s%s-n -q -d %s update", - program_path, -#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) - cvsauthenticate ? "-a " : "", - cvsencrypt ? "-x " : "", -#else - "", "", -#endif - current_parsed_root->original); - -#ifdef CLIENT_SUPPORT - /* Start the server; we'll close it after looping. */ - if (current_parsed_root->isremote) - { - start_server (); - ign_setup (); - } -#endif /* CLIENT_SUPPORT */ - - /* Remember the directory where "cvs release" was invoked because - all args are relative to this directory and we chdir around. - */ - if (save_cwd (&cwd)) - error_exit (); - - arg_start_idx = 0; - - for (i = arg_start_idx; i < argc; i++) - { - thisarg = argv[i]; - - if (isdir (thisarg)) - { - if (CVS_CHDIR (thisarg) < 0) - { - if (!really_quiet) - error (0, errno, "can't chdir to: %s", thisarg); - continue; - } - if (!isdir (CVSADM)) - { - if (!really_quiet) - error (0, 0, "no repository directory: %s", thisarg); - if (restore_cwd (&cwd, NULL)) - error_exit (); - continue; - } - } - else - { - if (!really_quiet) - error (0, 0, "no such directory: %s", thisarg); - continue; - } - - if (!really_quiet) - { - int line_length, status; - - /* The "release" command piggybacks on "update", which - does the real work of finding out if anything is not - up-to-date with the repository. Then "release" prompts - the user, telling her how many files have been - modified, and asking if she still wants to do the - release. */ - fp = run_popen (update_cmd, "r"); - if (fp == NULL) - error (1, 0, "cannot run command %s", update_cmd); - - c = 0; - - while ((line_length = getline (&line, &line_allocated, fp)) >= 0) - { - if (strchr ("MARCZ", *line)) - c++; - (void) fputs (line, stdout); - } - if (line_length < 0 && !feof (fp)) - error (0, errno, "cannot read from subprocess"); - - /* If the update exited with an error, then we just want to - complain and go on to the next arg. Especially, we do - not want to delete the local copy, since it's obviously - not what the user thinks it is. */ - status = pclose (fp); - if (status != 0) - { - error (0, 0, "unable to release `%s' (%d)", thisarg, status); - if (restore_cwd (&cwd, NULL)) - error_exit (); - continue; - } - - printf ("You have [%d] altered files in this repository.\n", - c); - printf ("Are you sure you want to release %sdirectory `%s': ", - delete_flag ? "(and delete) " : "", thisarg); - c = !yesno (); - if (c) /* "No" */ - { - (void) fprintf (stderr, "** `%s' aborted by user choice.\n", - cvs_cmd_name); - if (restore_cwd (&cwd, NULL)) - error_exit (); - continue; - } - } - - /* Note: client.c doesn't like to have other code - changing the current directory on it. So a fair amount - of effort is needed to make sure it doesn't get confused - about the directory and (for example) overwrite - CVS/Entries file in the wrong directory. See release-17 - through release-23. */ - - if (restore_cwd (&cwd, NULL)) - error_exit (); - - if (1 -#ifdef CLIENT_SUPPORT - && !(current_parsed_root->isremote - && (!supported_request ("noop") - || !supported_request ("Notify"))) -#endif - ) - { - int argc = 2; - char *argv[3]; - argv[0] = "dummy"; - argv[1] = thisarg; - argv[2] = NULL; - err += unedit (argc, argv); - if (restore_cwd (&cwd, NULL)) - error_exit (); - } - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - send_to_server ("Argument ", 0); - send_to_server (thisarg, 0); - send_to_server ("\012", 1); - send_to_server ("release\012", 0); - } - else -#endif /* CLIENT_SUPPORT */ - { - history_write ('F', thisarg, "", thisarg, ""); /* F == Free */ - } - - if (delete_flag) - { - /* FIXME? Shouldn't this just delete the CVS-controlled - files and, perhaps, the files that would normally be - ignored and leave everything else? */ - - if (unlink_file_dir (thisarg) < 0) - error (0, errno, "deletion of directory %s failed", thisarg); - } - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - /* FIXME: - * Is there a good reason why get_server_responses() isn't - * responsible for restoring its initial directory itself when - * finished? - */ - err += get_server_responses (); - - if (restore_cwd (&cwd, NULL)) - error_exit (); - } -#endif /* CLIENT_SUPPORT */ - } - - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - /* Unfortunately, client.c doesn't offer a way to close - the connection without waiting for responses. The extra - network turnaround here is quite unnecessary other than - that.... */ - send_to_server ("noop\012", 0); - err += get_responses_and_close (); - } -#endif /* CLIENT_SUPPORT */ - - free (update_cmd); - if (line != NULL) - free (line); - return err; -} diff --git a/contrib/cvs/src/remove.c b/contrib/cvs/src/remove.c deleted file mode 100644 index a09cfd4..0000000 --- a/contrib/cvs/src/remove.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Remove a File - * - * Removes entries from the present version. The entries will be removed from - * the RCS repository upon the next "commit". - * - * "remove" accepts no options, only file names that are to be removed. The - * file must not exist in the current directory for "remove" to work - * correctly. - */ - -#include "cvs.h" - -#ifdef CLIENT_SUPPORT -static int remove_force_fileproc PROTO ((void *callerdat, - struct file_info *finfo)); -#endif -static int remove_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static Dtype remove_dirproc PROTO ((void *callerdat, const char *dir, - const char *repos, const char *update_dir, - List *entries)); - -static int force; -static int local; -static int removed_files; -static int existing_files; - -static const char *const remove_usage[] = -{ - "Usage: %s %s [-flR] [files...]\n", - "\t-f\tDelete the file before removing it.\n", - "\t-l\tProcess this directory only (not recursive).\n", - "\t-R\tProcess directories recursively.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -int -cvsremove (argc, argv) - int argc; - char **argv; -{ - int c, err; - - if (argc == -1) - usage (remove_usage); - - optind = 0; - while ((c = getopt (argc, argv, "+flR")) != -1) - { - switch (c) - { - case 'f': - force = 1; - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case '?': - default: - usage (remove_usage); - break; - } - } - argc -= optind; - argv += optind; - - wrap_setup (); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) { - /* Call expand_wild so that the local removal of files will - work. It's ok to do it always because we have to send the - file names expanded anyway. */ - expand_wild (argc, argv, &argc, &argv); - - if (force) - { - if (!noexec) - { - start_recursion (remove_force_fileproc, (FILESDONEPROC) NULL, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, - (void *) NULL, argc, argv, local, W_LOCAL, - 0, CVS_LOCK_NONE, (char *) NULL, 0, - (char *) NULL); - } - /* else FIXME should probably act as if the file doesn't exist - in doing the following checks. */ - } - - start_server (); - ign_setup (); - if (local) - send_arg("-l"); - send_arg ("--"); - /* 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 (); - } -#endif - - /* start the recursion processor */ - err = start_recursion (remove_fileproc, (FILESDONEPROC) NULL, - remove_dirproc, (DIRLEAVEPROC) NULL, NULL, - argc, argv, - local, W_LOCAL, 0, CVS_LOCK_READ, (char *) NULL, 1, - (char *) NULL); - - if (removed_files && !really_quiet) - error (0, 0, "use '%s commit' to remove %s permanently", program_name, - (removed_files == 1) ? "this file" : "these files"); - - if (existing_files) - error (0, 0, - ((existing_files == 1) ? - "%d file exists; remove it first" : - "%d files exist; remove them first"), - existing_files); - - return (err); -} - -#ifdef CLIENT_SUPPORT - -/* - * This is called via start_recursion if we are running as the client - * and the -f option was used. We just physically remove the file. - */ - -/*ARGSUSED*/ -static int -remove_force_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - if (CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno)) - error (0, errno, "unable to remove %s", finfo->fullname); - return 0; -} - -#endif - -/* - * remove the file, only if it has already been physically removed - */ -/* ARGSUSED */ -static int -remove_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - Vers_TS *vers; - - if (force) - { - if (!noexec) - { - if ( CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno)) - { - error (0, errno, "unable to remove %s", finfo->fullname); - } - } - /* else FIXME should probably act as if the file doesn't exist - in doing the following checks. */ - } - - vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0); - - if (vers->ts_user != NULL) - { - existing_files++; - if (!quiet) - error (0, 0, "file `%s' still in working directory", - finfo->fullname); - } - else if (vers->vn_user == NULL) - { - if (!quiet) - error (0, 0, "nothing known about `%s'", finfo->fullname); - } - else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') - { - char *fname; - - /* - * It's a file that has been added, but not commited yet. So, - * remove the ,t file for it and scratch it from the - * entries file. */ - Scratch_Entry (finfo->entries, finfo->file); - fname = xmalloc (strlen (finfo->file) - + sizeof (CVSADM) - + sizeof (CVSEXT_LOG) - + 10); - (void) sprintf (fname, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG); - if (unlink_file (fname) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", CVSEXT_LOG); - if (!quiet) - error (0, 0, "removed `%s'", finfo->fullname); - -#ifdef SERVER_SUPPORT - if (server_active) - server_checked_in (finfo->file, finfo->update_dir, finfo->repository); -#endif - free (fname); - } - else if (vers->vn_user[0] == '-') - { - if (!quiet) - error (0, 0, "file `%s' already scheduled for removal", - finfo->fullname); - } - else if (vers->tag != NULL && isdigit ((unsigned char) *vers->tag)) - { - /* Commit will just give an error, and so there seems to be - little reason to allow the remove. I mean, conflicts that - arise out of parallel development are one thing, but conflicts - that arise from sticky tags are quite another. - - I would have thought that non-branch sticky tags should be the - same but at least now, removing a file with a non-branch sticky - tag means to delete the tag from the file. I'm not sure that - is a good behavior, but until it is changed, we need to allow - it. */ - error (0, 0, "\ -cannot remove file `%s' which has a numeric sticky tag of `%s'", - finfo->fullname, vers->tag); - } - else if (vers->date != NULL) - { - /* Commit will just give an error, and so there seems to be - little reason to allow the remove. */ - error (0, 0, "\ -cannot remove file `%s' which has a sticky date of `%s'", - finfo->fullname, vers->date); - } - else - { - char *fname; - - /* Re-register it with a negative version number. */ - fname = xmalloc (strlen (vers->vn_user) + 5); - (void) strcpy (fname, "-"); - (void) strcat (fname, vers->vn_user); - Register (finfo->entries, finfo->file, fname, vers->ts_rcs, vers->options, - vers->tag, vers->date, vers->ts_conflict); - if (!quiet) - error (0, 0, "scheduling `%s' for removal", finfo->fullname); - removed_files++; - -#ifdef SERVER_SUPPORT - if (server_active) - server_checked_in (finfo->file, finfo->update_dir, finfo->repository); -#endif - free (fname); - } - - freevers_ts (&vers); - return (0); -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -remove_dirproc (callerdat, dir, repos, update_dir, entries) - void *callerdat; - const char *dir; - const char *repos; - const char *update_dir; - List *entries; -{ - if (!quiet) - error (0, 0, "Removing %s", update_dir); - return (R_PROCESS); -} diff --git a/contrib/cvs/src/repos.c b/contrib/cvs/src/repos.c deleted file mode 100644 index 202d92d..0000000 --- a/contrib/cvs/src/repos.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - */ - -#include <assert.h> -#include "cvs.h" -#include "getline.h" - -/* Determine the name of the RCS repository for directory DIR in the - current working directory, or for the current working directory - itself if DIR is NULL. Returns the name in a newly-malloc'd - string. On error, gives a fatal error and does not return. - UPDATE_DIR is the path from where cvs was invoked (for use in error - messages), and should contain DIR as its last component. - UPDATE_DIR can be NULL to signify the directory in which cvs was - invoked. */ - -char * -Name_Repository (dir, update_dir) - const char *dir; - const char *update_dir; -{ - FILE *fpin; - const char *xupdate_dir; - char *repos = NULL; - size_t repos_allocated = 0; - char *tmp; - char *cp; - - if (update_dir && *update_dir) - xupdate_dir = update_dir; - else - xupdate_dir = "."; - - if (dir != NULL) - { - tmp = xmalloc (strlen (dir) + sizeof (CVSADM_REP) + 10); - (void) sprintf (tmp, "%s/%s", dir, CVSADM_REP); - } - else - tmp = xstrdup (CVSADM_REP); - - /* - * The assumption here is that the repository is always contained in the - * first line of the "Repository" file. - */ - fpin = CVS_FOPEN (tmp, "r"); - - if (fpin == NULL) - { - int save_errno = errno; - char *cvsadm; - - if (dir != NULL) - { - cvsadm = xmalloc (strlen (dir) + sizeof (CVSADM) + 10); - (void) sprintf (cvsadm, "%s/%s", dir, CVSADM); - } - else - cvsadm = xstrdup (CVSADM); - - if (!isdir (cvsadm)) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (1, 0, "there is no version here; do '%s checkout' first", - program_name); - } - free (cvsadm); - - if (existence_error (save_errno)) - { - /* FIXME: This is a very poorly worded error message. It - occurs at least in the case where the user manually - creates a directory named CVS, so the error message - should be more along the lines of "CVS directory found - without administrative files; use CVS to create the CVS - directory, or rename it to something else if the - intention is to store something besides CVS - administrative files". */ - error (0, 0, "in directory %s:", xupdate_dir); - error (1, 0, "*PANIC* administration files missing"); - } - - error (1, save_errno, "cannot open %s", tmp); - } - - if (getline (&repos, &repos_allocated, fpin) < 0) - { - /* FIXME: should be checking for end of file separately. */ - error (0, 0, "in directory %s:", xupdate_dir); - error (1, errno, "cannot read %s", CVSADM_REP); - } - if (fclose (fpin) < 0) - error (0, errno, "cannot close %s", tmp); - free (tmp); - - if ((cp = strrchr (repos, '\n')) != NULL) - *cp = '\0'; /* strip the newline */ - - /* - * If this is a relative repository pathname, turn it into an absolute - * one by tacking on the CVSROOT environment variable. If the CVSROOT - * environment variable is not set, die now. - */ - if (! isabsolute(repos)) - { - char *newrepos; - - if (current_parsed_root == NULL) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (0, 0, "must set the CVSROOT environment variable\n"); - 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 (current_parsed_root->directory) - + strlen (repos) + 2); - sprintf (newrepos, "%s/%s", current_parsed_root->directory, repos); - free (repos); - repos = newrepos; - } - - Sanitize_Repository_Name (repos); - - return repos; -} - - - -/* - * Return a pointer to the repository name relative to CVSROOT from a - * possibly fully qualified repository - */ -const char * -Short_Repository (repository) - const char *repository; -{ - if (repository == NULL) - return NULL; - - /* If repository matches CVSroot at the beginning, strip off CVSroot */ - /* And skip leading '/' in rep, in case CVSroot ended with '/'. */ - if (strncmp (current_parsed_root->directory, repository, - strlen (current_parsed_root->directory)) == 0) - { - const char *rep = repository + strlen (current_parsed_root->directory); - return (*rep == '/') ? rep+1 : rep; - } - else - return repository; -} - - - -/* Sanitize the repository name (in place) by removing trailing - * slashes and a trailing "." if present. It should be safe for - * callers to use strcat and friends to create repository names. - * Without this check, names like "/path/to/repos/./foo" and - * "/path/to/repos//foo" would be created. For example, one - * significant case is the CVSROOT-detection code in commit.c. It - * decides whether or not it needs to rebuild the administrative file - * database by doing a string compare. If we've done a `cvs co .' to - * get the CVSROOT files, "/path/to/repos/./CVSROOT" and - * "/path/to/repos/CVSROOT" are the arguments that are compared! - * - * This function ends up being called from the same places as - * strip_path, though what it does is much more conservative. Many - * comments about this operation (which was scattered around in - * several places in the source code) ran thus: - * - * ``repository ends with "/."; omit it. This sort of thing used - * to be taken care of by strip_path. Now we try to be more - * selective. I suspect that it would be even better to push it - * back further someday, so that the trailing "/." doesn't get into - * repository in the first place, but we haven't taken things that - * far yet.'' --Jim Kingdon (recurse.c, 07-Sep-97) - */ - -void -Sanitize_Repository_Name (repository) - char *repository; -{ - size_t len; - - assert (repository != NULL); - - strip_trailing_slashes (repository); - - len = strlen (repository); - if (len >= 2 - && repository[len - 1] == '.' - && ISDIRSEP (repository[len - 2])) - { - repository[len - 2] = '\0'; - } -} diff --git a/contrib/cvs/src/root.c b/contrib/cvs/src/root.c deleted file mode 100644 index 44d1f9a..0000000 --- a/contrib/cvs/src/root.c +++ /dev/null @@ -1,864 +0,0 @@ -/* - * Copyright (C) 1986-2008 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Poritons Copyright (c) 1992, Mark D. Baushke - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Name of Root - * - * Determine the path to the CVSROOT and set "Root" accordingly. - */ - -#include "cvs.h" -#include <assert.h> -#include "getline.h" - -/* Printable names for things in the current_parsed_root->method enum variable. - Watch out if the enum is changed in cvs.h! */ - -const char method_names[][16] = { - "undefined", "local", "server (rsh)", "pserver", - "kserver", "gserver", "ext", "extssh", "fork" -}; - -#ifndef DEBUG - -cvsroot_t * -Name_Root (dir, update_dir) - const char *dir; - const char *update_dir; -{ - FILE *fpin; - cvsroot_t *ret; - const char *xupdate_dir; - char *root = NULL; - size_t root_allocated = 0; - char *tmp; - char *cvsadm; - char *cp; - int len; - - if (update_dir && *update_dir) - xupdate_dir = update_dir; - else - xupdate_dir = "."; - - if (dir != NULL) - { - cvsadm = xmalloc (strlen (dir) + sizeof (CVSADM) + 10); - (void) sprintf (cvsadm, "%s/%s", dir, CVSADM); - tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ROOT) + 10); - (void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT); - } - else - { - cvsadm = xstrdup (CVSADM); - tmp = xstrdup (CVSADM_ROOT); - } - - /* - * Do not bother looking for a readable file if there is no cvsadm - * directory present. - * - * It is possible that not all repositories will have a CVS/Root - * file. This is ok, but the user will need to specify -d - * /path/name or have the environment variable CVSROOT set in - * order to continue. */ - if ((!isdir (cvsadm)) || (!isreadable (tmp))) - { - ret = NULL; - goto out; - } - - /* - * The assumption here is that the CVS Root is always contained in the - * first line of the "Root" file. - */ - fpin = open_file (tmp, "r"); - - if ((len = getline (&root, &root_allocated, fpin)) < 0) - { - int saved_errno = errno; - /* FIXME: should be checking for end of file separately; errno - is not set in that case. */ - error (0, 0, "in directory %s:", xupdate_dir); - error (0, saved_errno, "cannot read %s", CVSADM_ROOT); - error (0, 0, "please correct this problem"); - ret = NULL; - goto out; - } - fclose (fpin); - cp = root + len - 1; - if (*cp == '\n') - *cp = '\0'; /* strip the newline */ - - /* - * root now contains a candidate for CVSroot. It must be an - * absolute pathname or specify a remote server. - */ - - ret = parse_cvsroot (root); - if (ret == NULL) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (0, 0, - "ignoring %s because it does not contain a valid root.", - CVSADM_ROOT); - goto out; - } - - if (!ret->isremote && !isdir (ret->directory)) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (0, 0, - "ignoring %s because it specifies a non-existent repository %s", - CVSADM_ROOT, root); - free_cvsroot_t (ret); - ret = NULL; - goto out; - } - - - out: - free (cvsadm); - free (tmp); - if (root != NULL) - free (root); - return ret; -} - - - -/* - * Write the CVS/Root file so that the environment variable CVSROOT - * and/or the -d option to cvs will be validated or not necessary for - * future work. - */ -void -Create_Root (dir, rootdir) - const char *dir; - const char *rootdir; -{ - FILE *fout; - char *tmp; - - if (noexec) - return; - - /* record the current cvs root */ - - if (rootdir != NULL) - { - if (dir != NULL) - { - tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ROOT) + 10); - (void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT); - } - else - tmp = xstrdup (CVSADM_ROOT); - - fout = open_file (tmp, "w+"); - if (fprintf (fout, "%s\n", rootdir) < 0) - error (1, errno, "write to %s failed", tmp); - if (fclose (fout) == EOF) - error (1, errno, "cannot close %s", tmp); - free (tmp); - } -} - -#endif /* ! DEBUG */ - - -/* The root_allow_* stuff maintains a list of legal CVSROOT - directories. Then we can check against them when a remote user - hands us a CVSROOT directory. */ - -static int root_allow_count; -static char **root_allow_vector; -static int root_allow_size; - -int -root_allow_used () -{ - return root_allow_count; -} - -void -root_allow_add (arg) - char *arg; -{ - char *p; - - if (root_allow_size <= root_allow_count) - { - if (root_allow_size == 0) - { - root_allow_size = 1; - root_allow_vector = - (char **) xmalloc (root_allow_size * sizeof (char *)); - } - else - { - root_allow_size *= 2; - root_allow_vector = - (char **) xrealloc (root_allow_vector, - root_allow_size * sizeof (char *)); - } - - if (root_allow_vector == NULL) - { - no_memory: - /* Strictly speaking, we're not supposed to output anything - now. But we're about to exit(), give it a try. */ - printf ("E Fatal server error, aborting.\n\ -error ENOMEM Virtual memory exhausted.\n"); - - error_exit (); - } - } - p = xmalloc (strlen (arg) + 1); - if (p == NULL) - goto no_memory; - strcpy (p, arg); - root_allow_vector[root_allow_count++] = p; -} - -void -root_allow_free () -{ - if (root_allow_vector != NULL) - free_names (&root_allow_count, root_allow_vector); - root_allow_size = 0; -} - -int -root_allow_ok (arg) - char *arg; -{ - int i; - - if (root_allow_count == 0) - { - /* Probably someone upgraded from CVS before 1.9.10 to 1.9.10 - or later without reading the documentation about - --allow-root. Printing an error here doesn't disclose any - particularly useful information to an attacker because a - CVS server configured in this way won't let *anyone* in. */ - - /* Note that we are called from a context where we can spit - back "error" rather than waiting for the next request which - expects responses. */ - printf ("\ -error 0 Server configuration missing --allow-root in inetd.conf\n"); - error_exit (); - } - - for (i = 0; i < root_allow_count; ++i) - if (strcmp (root_allow_vector[i], arg) == 0) - return 1; - return 0; -} - - - -/* This global variable holds the global -d option. It is NULL if -d - was not used, which means that we must get the CVSroot information - from the CVSROOT environment variable or from a CVS/Root file. */ -char *CVSroot_cmdline; - - - -/* FIXME - Deglobalize this. */ -cvsroot_t *current_parsed_root = NULL; - - - -/* allocate and initialize a cvsroot_t - * - * We must initialize the strings to NULL so we know later what we should - * free - * - * Some of the other zeroes remain meaningful as, "never set, use default", - * or the like - */ -static cvsroot_t * -new_cvsroot_t () -{ - cvsroot_t *newroot; - - /* gotta store it somewhere */ - newroot = xmalloc(sizeof(cvsroot_t)); - - newroot->original = NULL; - newroot->method = null_method; - newroot->isremote = 0; -#ifdef CLIENT_SUPPORT - newroot->username = NULL; - newroot->password = NULL; - newroot->hostname = NULL; - newroot->port = 0; - newroot->directory = NULL; - newroot->proxy_hostname = NULL; - newroot->proxy_port = 0; -#endif /* CLIENT_SUPPORT */ - - return newroot; -} - - - -/* Dispose of a cvsroot_t and its component parts */ -void -free_cvsroot_t (root) - cvsroot_t *root; -{ - if (root->original != NULL) - free (root->original); - if (root->directory != NULL) - free (root->directory); -#ifdef CLIENT_SUPPORT - if (root->username != NULL) - free (root->username); - if (root->password != NULL) - { - /* I like to be paranoid */ - memset (root->password, 0, strlen (root->password)); - free (root->password); - } - if (root->hostname != NULL) - free (root->hostname); - if (root->proxy_hostname != NULL) - free (root->proxy_hostname); -#endif /* CLIENT_SUPPORT */ - free (root); -} - - - -/* - * Parse a CVSROOT string to allocate and return a new cvsroot_t structure. - * Valid specifications are: - * - * :(gserver|kserver|pserver):[[user][:password]@]host[:[port]]/path - * [:(ext|server):][[user]@]host[:]/path - * [:local:[e:]]/path - * :fork:/path - * - * INPUTS - * root_in C String containing the CVSROOT to be parsed. - * - * RETURNS - * A pointer to a newly allocated cvsroot_t structure upon success and - * NULL upon failure. The caller is responsible for disposing of - * new structures with a call to free_cvsroot_t(). - * - * NOTES - * This would have been a lot easier to write in Perl. - * - * SEE ALSO - * free_cvsroot_t() - */ -cvsroot_t * -parse_cvsroot (root_in) - const char *root_in; -{ - cvsroot_t *newroot; /* the new root to be returned */ - char *cvsroot_save; /* what we allocated so we can dispose - * it when finished */ - char *firstslash; /* save where the path spec starts - * while we parse - * [[user][:password]@]host[:[port]] - */ - char *cvsroot_copy, *p, *q; /* temporary pointers for parsing */ -#ifdef CLIENT_SUPPORT - int check_hostname, no_port, no_password; -#endif /* CLIENT_SUPPORT */ - - assert (root_in); - - /* allocate some space */ - newroot = new_cvsroot_t(); - - /* save the original string */ - newroot->original = xstrdup (root_in); - - /* and another copy we can munge while parsing */ - cvsroot_save = cvsroot_copy = xstrdup (root_in); - - if (*cvsroot_copy == ':') - { - char *method = ++cvsroot_copy; - - /* Access method specified, as in - * "cvs -d :(gserver|kserver|pserver):[[user][:password]@]host[:[port]]/path", - * "cvs -d [:(ext|server):][[user]@]host[:]/path", - * "cvs -d :local:e:\path", - * "cvs -d :fork:/path". - * We need to get past that part of CVSroot before parsing the - * rest of it. - */ - - if (! (p = strchr (method, ':'))) - { - error (0, 0, "No closing `:' on method in CVSROOT."); - goto error_exit; - } - *p = '\0'; - cvsroot_copy = ++p; - -#ifdef CLIENT_SUPPORT - /* Look for method options, for instance, proxy, proxyport. - * We don't handle these, but we like to try and warn the user that - * they are being ignored. - */ - if ((p = strchr (method, ';')) != NULL) - { - *p++ = '\0'; - if (!really_quiet) - { - error (0, 0, -"WARNING: Ignoring method options found in CVSROOT: `%s'.", - p); - error (0, 0, -"Use CVS version 1.12.7 or later to handle method options."); - } - } -#endif /* CLIENT_SUPPORT */ - - /* Now we have an access method -- see if it's valid. */ - - if (strcmp (method, "local") == 0) - newroot->method = local_method; - else if (strcmp (method, "pserver") == 0) - newroot->method = pserver_method; - else if (strcmp (method, "kserver") == 0) - newroot->method = kserver_method; - else if (strcmp (method, "gserver") == 0) - newroot->method = gserver_method; - else if (strcmp (method, "server") == 0) - newroot->method = server_method; - else if (strcmp (method, "ext") == 0) - newroot->method = ext_method; - else if (strcmp (method, "extssh") == 0) - newroot->method = extssh_method; - else if (strcmp (method, "fork") == 0) - newroot->method = fork_method; - else - { - error (0, 0, "Unknown method (`%s') in CVSROOT.", method); - goto error_exit; - } - } - else - { - /* If the method isn't specified, assume EXT_METHOD if the string looks - like a relative path and LOCAL_METHOD otherwise. */ - - newroot->method = ((*cvsroot_copy != '/' && strchr (cvsroot_copy, '/')) - ? ext_method - : local_method); - } - - newroot->isremote = (newroot->method != local_method); - - if ((newroot->method != local_method) - && (newroot->method != fork_method)) - { - /* split the string into [[user][:password]@]host[:[port]] & /path - * - * this will allow some characters such as '@' & ':' to remain unquoted - * in the path portion of the spec - */ - if ((p = strchr (cvsroot_copy, '/')) == NULL) - { - error (0, 0, "CVSROOT requires a path spec:"); - error (0, 0, -":(gserver|kserver|pserver):[[user][:password]@]host[:[port]]/path"); - error (0, 0, "[:(ext|server):][[user]@]host[:]/path"); - goto error_exit; - } - firstslash = p; /* == NULL if '/' not in string */ - *p = '\0'; - - /* Don't parse username, password, hostname, or port without client - * support. - */ -#ifdef CLIENT_SUPPORT - /* Check to see if there is a username[:password] in the string. */ - if ((p = strchr (cvsroot_copy, '@')) != NULL) - { - *p = '\0'; - /* check for a password */ - if ((q = strchr (cvsroot_copy, ':')) != NULL) - { - *q = '\0'; - newroot->password = xstrdup (++q); - /* Don't check for *newroot->password == '\0' since - * a user could conceivably wish to specify a blank password - * - * (newroot->password == NULL means to use the - * password from .cvspass) - */ - } - - /* copy the username */ - if (*cvsroot_copy != '\0') - /* a blank username is impossible, so leave it NULL in that - * case so we know to use the default username - */ - newroot->username = xstrdup (cvsroot_copy); - - cvsroot_copy = ++p; - } - - /* now deal with host[:[port]] */ - - /* the port */ - if ((p = strchr (cvsroot_copy, ':')) != NULL) - { - *p++ = '\0'; - if (strlen(p)) - { - q = p; - if (*q == '-') q++; - while (*q) - { - if (!isdigit(*q++)) - { - error (0, 0, -"CVSROOT may only specify a positive, non-zero, integer port (not `%s').", - p); - error (0, 0, - "Perhaps you entered a relative pathname?"); - goto error_exit; - } - } - if ((newroot->port = atoi (p)) <= 0) - { - error (0, 0, -"CVSROOT may only specify a positive, non-zero, integer port (not `%s').", - p); - error (0, 0, "Perhaps you entered a relative pathname?"); - goto error_exit; - } - } - } - - /* copy host */ - if (*cvsroot_copy != '\0') - /* blank hostnames are invalid, but for now leave the field NULL - * and catch the error during the sanity checks later - */ - newroot->hostname = xstrdup (cvsroot_copy); - - /* restore the '/' */ - cvsroot_copy = firstslash; - *cvsroot_copy = '/'; -#endif /* CLIENT_SUPPORT */ - } - - /* - * Parse the path for all methods. - */ - /* Here & local_cvsroot() should be the only places this needs to be - * called on a CVSROOT now. cvsroot->original is saved for error messages - * and, otherwise, we want no trailing slashes. - */ - Sanitize_Repository_Name( cvsroot_copy ); - newroot->directory = xstrdup(cvsroot_copy); - - /* - * Do various sanity checks. - */ - -#if ! defined (CLIENT_SUPPORT) && ! defined (DEBUG) - if (newroot->method != local_method) - { - error (0, 0, "CVSROOT is set for a remote access method but your"); - error (0, 0, "CVS executable doesn't support it."); - goto error_exit; - } -#endif - -#if ! defined (SERVER_SUPPORT) && ! defined (DEBUG) - if (newroot->method == fork_method) - { - error (0, 0, "CVSROOT is set to use the :fork: access method but your"); - error (0, 0, "CVS executable doesn't support it."); - goto error_exit; - } -#endif - -#ifdef CLIENT_SUPPORT - if (newroot->username && ! newroot->hostname) - { - error (0, 0, "Missing hostname in CVSROOT."); - goto error_exit; - } - - check_hostname = 0; - no_password = 1; - no_port = 0; -#endif /* CLIENT_SUPPORT */ - switch (newroot->method) - { - case local_method: -#ifdef CLIENT_SUPPORT - if (newroot->username || newroot->hostname) - { - error (0, 0, "Can't specify hostname and username in CVSROOT"); - error (0, 0, "when using local access method."); - goto error_exit; - } - no_port = 1; - /* no_password already set */ -#endif /* CLIENT_SUPPORT */ - /* cvs.texinfo has always told people that CVSROOT must be an - absolute pathname. Furthermore, attempts to use a relative - pathname produced various errors (I couldn't get it to work), - so there would seem to be little risk in making this a fatal - error. */ - if (!isabsolute (newroot->directory)) - { - error (0, 0, "CVSROOT must be an absolute pathname (not `%s')", - newroot->directory); - error (0, 0, "when using local access method."); - goto error_exit; - } - break; -#ifdef CLIENT_SUPPORT - 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 (newroot->username || newroot->hostname) - { - error (0, 0, "Can't specify hostname and username in CVSROOT"); - error (0, 0, "when using fork access method."); - goto error_exit; - } - newroot->hostname = xstrdup("server"); /* for error messages */ - if (!isabsolute (newroot->directory)) - { - error (0, 0, "CVSROOT must be an absolute pathname (not `%s')", - newroot->directory); - error (0, 0, "when using fork access method."); - goto error_exit; - } - no_port = 1; - /* no_password already set */ - break; - case kserver_method: -# ifndef HAVE_KERBEROS - error (0, 0, "CVSROOT is set for a kerberos access method but your"); - error (0, 0, "CVS executable doesn't support it."); - goto error_exit; -# else - check_hostname = 1; - /* no_password already set */ - break; -# endif - case gserver_method: -# ifndef HAVE_GSSAPI - error (0, 0, "CVSROOT is set for a GSSAPI access method but your"); - error (0, 0, "CVS executable doesn't support it."); - goto error_exit; -# else - check_hostname = 1; - /* no_password already set */ - break; -# endif - case server_method: - case ext_method: - case extssh_method: - no_port = 1; - /* no_password already set */ - check_hostname = 1; - break; - case pserver_method: - no_password = 0; - check_hostname = 1; - break; -#endif /* CLIENT_SUPPORT */ - default: - error (1, 0, "Invalid method found in parse_cvsroot"); - } - -#ifdef CLIENT_SUPPORT - if (no_password && newroot->password) - { - error (0, 0, "CVSROOT password specification is only valid for"); - error (0, 0, "pserver connection method."); - goto error_exit; - } - - if (check_hostname && !newroot->hostname) - { - error (0, 0, "Didn't specify hostname in CVSROOT."); - goto error_exit; - } - - if (no_port && newroot->port) - { - error (0, 0, "CVSROOT port specification is only valid for gserver, kserver,"); - error (0, 0, "and pserver connection methods."); - goto error_exit; - } -#endif /* CLIENT_SUPPORT */ - - if (*newroot->directory == '\0') - { - error (0, 0, "Missing directory in CVSROOT."); - goto error_exit; - } - - /* Hooray! We finally parsed it! */ - free (cvsroot_save); - return newroot; - -error_exit: - free (cvsroot_save); - free_cvsroot_t (newroot); - return NULL; -} - - - -#ifdef AUTH_CLIENT_SUPPORT -/* Use root->username, root->hostname, root->port, and root->directory - * to create a normalized CVSROOT fit for the .cvspass file - * - * username defaults to the result of getcaller() - * port defaults to the result of get_cvs_port_number() - * - * FIXME - we could cache the canonicalized version of a root inside the - * cvsroot_t, but we'd have to un'const the input here and stop expecting the - * caller to be responsible for our return value - */ -char * -normalize_cvsroot (root) - const cvsroot_t *root; -{ - char *cvsroot_canonical; - char *p, *hostname, *username; - char port_s[64]; - - assert (root && root->hostname && root->directory); - - /* get the appropriate port string */ - sprintf (port_s, "%d", get_cvs_port_number (root)); - - /* use a lower case hostname since we know hostnames are case insensitive */ - /* Some logic says we should be tacking our domain name on too if it isn't - * there already, but for now this works. Reverse->Forward lookups are - * almost certainly too much since that would make CVS immune to some of - * the DNS trickery that makes life easier for sysadmins when they want to - * move a repository or the like - */ - p = hostname = xstrdup(root->hostname); - while (*p) - { - *p = tolower(*p); - p++; - } - - /* get the username string */ - username = root->username ? root->username : getcaller(); - cvsroot_canonical = xmalloc ( strlen(username) - + strlen(hostname) + strlen(port_s) - + strlen(root->directory) + 12); - sprintf (cvsroot_canonical, ":pserver:%s@%s:%s%s", - username, hostname, port_s, root->directory); - - free (hostname); - return cvsroot_canonical; -} -#endif /* AUTH_CLIENT_SUPPORT */ - - - -/* allocate and return a cvsroot_t structure set up as if we're using the local - * repository DIR. */ -cvsroot_t * -local_cvsroot (dir) - const char *dir; -{ - cvsroot_t *newroot = new_cvsroot_t(); - - newroot->original = xstrdup(dir); - newroot->method = local_method; - newroot->directory = xstrdup(dir); - /* Here and parse_cvsroot() should be the only places this needs to be - * called on a CVSROOT now. cvsroot->original is saved for error messages - * and, otherwise, we want no trailing slashes. - */ - Sanitize_Repository_Name( newroot->directory ); - return newroot; -} - - - -#ifdef DEBUG -/* This is for testing the parsing function. Use - - gcc -I. -I.. -I../lib -DDEBUG root.c -o root - - to compile. */ - -#include <stdio.h> - -char *program_name = "testing"; -char *cvs_cmd_name = "parse_cvsroot"; /* XXX is this used??? */ - -/* Toy versions of various functions when debugging under unix. Yes, - these make various bad assumptions, but they're pretty easy to - debug when something goes wrong. */ - -void -error_exit PROTO ((void)) -{ - exit (1); -} - -int -isabsolute (dir) - const char *dir; -{ - return (dir && (*dir == '/')); -} - -void -main (argc, argv) - int argc; - char *argv[]; -{ - program_name = argv[0]; - - if (argc != 2) - { - fprintf (stderr, "Usage: %s <CVSROOT>\n", program_name); - exit (2); - } - - if ((current_parsed_root = parse_cvsroot (argv[1])) == NULL) - { - fprintf (stderr, "%s: Parsing failed.\n", program_name); - exit (1); - } - printf ("CVSroot: %s\n", argv[1]); - printf ("current_parsed_root->method: %s\n", method_names[current_parsed_root->method]); - printf ("current_parsed_root->username: %s\n", - current_parsed_root->username ? current_parsed_root->username : "NULL"); - printf ("current_parsed_root->hostname: %s\n", - current_parsed_root->hostname ? current_parsed_root->hostname : "NULL"); - printf ("current_parsed_root->directory: %s\n", current_parsed_root->directory); - - exit (0); - /* NOTREACHED */ -} -#endif diff --git a/contrib/cvs/src/root.h b/contrib/cvs/src/root.h deleted file mode 100644 index 089b694..0000000 --- a/contrib/cvs/src/root.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS kit. - */ - -/* CVSroot data structures */ - -/* Access method specified in CVSroot. */ -typedef enum { - null_method, - local_method, - server_method, - pserver_method, - kserver_method, - gserver_method, - ext_method, - extssh_method, - fork_method -} CVSmethod; -extern const char method_names[][16]; /* change this in root.c if you change - the enum above */ - -typedef struct cvsroot_s { - char *original; /* The complete source CVSroot string. */ - CVSmethod method; /* One of the enum values above. */ - char *directory; /* The directory name. */ - unsigned char isremote; /* Nonzero if we are doing remote access. */ -#ifdef CLIENT_SUPPORT - char *username; /* The username or NULL if method == local. */ - char *password; /* The password or NULL if method == local. */ - char *hostname; /* The hostname or NULL if method == local. */ - int port; /* The port or zero if method == local. */ - char *proxy_hostname; /* The hostname of the proxy server, or NULL - * when method == local or no proxy will be - * used. - */ - int proxy_port; /* The port of the proxy or zero, as above. */ -#endif /* CLIENT_SUPPORT */ -} cvsroot_t; - -cvsroot_t *Name_Root PROTO((const char *dir, const char *update_dir)); -void free_cvsroot_t PROTO((cvsroot_t *root_in)); -cvsroot_t *parse_cvsroot PROTO((const char *root)); -cvsroot_t *local_cvsroot PROTO((const char *dir)); -void Create_Root PROTO((const char *dir, const char *rootdir)); -void root_allow_add PROTO ((char *)); -void root_allow_free PROTO ((void)); -int root_allow_ok PROTO ((char *)); -int root_allow_used PROTO ((void)); diff --git a/contrib/cvs/src/run.c b/contrib/cvs/src/run.c deleted file mode 100644 index 98ae911..0000000 --- a/contrib/cvs/src/run.c +++ /dev/null @@ -1,578 +0,0 @@ -/* run.c --- routines for executing subprocesses. - - This file is part of GNU CVS. - - GNU CVS is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -#include "cvs.h" - -#ifndef HAVE_UNISTD_H -extern int execvp PROTO((char *file, char **argv)); -#endif - -static void run_add_arg PROTO((const char *s)); - -extern char *strtok (); - -/* - * To exec a program under CVS, first call run_setup() to setup initial - * arguments. The argument to run_setup will be parsed into whitespace - * separated words and added to the global run_argv list. - * - * Then, optionally call run_arg() for each additional argument that you'd like - * to pass to the executed program. - * - * Finally, call run_exec() to execute the program with the specified arguments. - * The execvp() syscall will be used, so that the PATH is searched correctly. - * File redirections can be performed in the call to run_exec(). - */ -static char **run_argv; -static int run_argc; -static size_t run_argc_allocated; - - - -void -run_arg_free_p (int argc, char **argv) -{ - int i; - for (i = 0; i < argc; i++) - free (argv[i]); -} - - - -/* VARARGS */ -void -run_setup (prog) - const char *prog; -{ - char *cp; - char *run_prog; - - /* clean out any malloc'ed values from run_argv */ - run_arg_free_p (run_argc, run_argv); - run_argc = 0; - - run_prog = xstrdup (prog); - - /* put each word into run_argv, allocating it as we go */ - for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t")) - run_add_arg (cp); - free (run_prog); -} - -void -run_arg (s) - const char *s; -{ - run_add_arg (s); -} - - - -void -run_add_arg_p (iargc, iarg_allocated, iargv, s) - int *iargc; - size_t *iarg_allocated; - char ***iargv; - const char *s; -{ - /* allocate more argv entries if we've run out */ - if (*iargc >= *iarg_allocated) - { - *iarg_allocated += 50; - *iargv = xrealloc (*iargv, *iarg_allocated * sizeof (char **)); - } - - if (s) - (*iargv)[(*iargc)++] = xstrdup (s); - else - (*iargv)[*iargc] = NULL; /* not post-incremented on purpose! */ -} - - - -static void -run_add_arg (s) - const char *s; -{ - run_add_arg_p (&run_argc, &run_argc_allocated, &run_argv, s); -} - - - -int -run_exec (stin, stout, sterr, flags) - const char *stin; - const char *stout; - const char *sterr; - int flags; -{ - int shin, shout, sherr; - int mode_out, mode_err; - int status; - int rc = -1; - int rerrno = 0; - int pid, w; - -#ifdef POSIX_SIGNALS - sigset_t sigset_mask, sigset_omask; - struct sigaction act, iact, qact; - -#else -#ifdef BSD_SIGNALS - int mask; - struct sigvec vec, ivec, qvec; - -#else - RETSIGTYPE (*istat) (), (*qstat) (); -#endif -#endif - - if (trace) - { -#ifdef SERVER_SUPPORT - cvs_outerr (server_active ? "S" : " ", 1); -#endif - cvs_outerr ("-> system(", 0); - run_print (stderr); - cvs_outerr (")\n", 0); - } - if (noexec && (flags & RUN_REALLY) == 0) - return 0; - - /* make sure that we are null terminated, since we didn't calloc */ - run_add_arg ((char *)0); - - /* setup default file descriptor numbers */ - shin = 0; - shout = 1; - sherr = 2; - - /* set the file modes for stdout and stderr */ - mode_out = mode_err = O_WRONLY | O_CREAT; - mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC); - mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC); - - if (stin && (shin = open (stin, O_RDONLY)) == -1) - { - rerrno = errno; - error (0, errno, "cannot open %s for reading (prog %s)", - stin, run_argv[0]); - goto out0; - } - if (stout && (shout = open (stout, mode_out, 0666)) == -1) - { - rerrno = errno; - error (0, errno, "cannot open %s for writing (prog %s)", - stout, run_argv[0]); - goto out1; - } - if (sterr && (flags & RUN_COMBINED) == 0) - { - if ((sherr = open (sterr, mode_err, 0666)) == -1) - { - rerrno = errno; - error (0, errno, "cannot open %s for writing (prog %s)", - sterr, run_argv[0]); - goto out2; - } - } - - /* Make sure we don't flush this twice, once in the subprocess. */ - cvs_flushout(); - cvs_flusherr(); - - /* The output files, if any, are now created. Do the fork and dups. - - We use vfork not so much for a performance boost (the - performance boost, if any, is modest on most modern unices), - but for the sake of systems without a memory management unit, - which find it difficult or impossible to implement fork at all - (e.g. Amiga). The other solution is spawn (see - windows-NT/run.c). */ - -#ifdef HAVE_VFORK - pid = vfork (); -#else - pid = fork (); -#endif - if (pid == 0) - { - if (shin != 0) - { - (void) dup2 (shin, 0); - (void) close (shin); - } - if (shout != 1) - { - (void) dup2 (shout, 1); - (void) close (shout); - } - if (flags & RUN_COMBINED) - (void) dup2 (1, 2); - else if (sherr != 2) - { - (void) dup2 (sherr, 2); - (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]); - _exit (127); - } - else if (pid == -1) - { - rerrno = errno; - goto out; - } - - /* the parent. Ignore some signals for now */ -#ifdef POSIX_SIGNALS - if (flags & RUN_SIGIGNORE) - { - act.sa_handler = SIG_IGN; - (void) sigemptyset (&act.sa_mask); - act.sa_flags = 0; - (void) sigaction (SIGINT, &act, &iact); - (void) sigaction (SIGQUIT, &act, &qact); - } - else - { - (void) sigemptyset (&sigset_mask); - (void) sigaddset (&sigset_mask, SIGINT); - (void) sigaddset (&sigset_mask, SIGQUIT); - (void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask); - } -#else -#ifdef BSD_SIGNALS - if (flags & RUN_SIGIGNORE) - { - memset ((char *)&vec, 0, sizeof (vec)); - vec.sv_handler = SIG_IGN; - (void) sigvec (SIGINT, &vec, &ivec); - (void) sigvec (SIGQUIT, &vec, &qvec); - } - else - mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT)); -#else - istat = signal (SIGINT, SIG_IGN); - qstat = signal (SIGQUIT, SIG_IGN); -#endif -#endif - - /* wait for our process to die and munge return status */ -#ifdef POSIX_SIGNALS - while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR) - ; -#else - while ((w = wait (&status)) != pid) - { - if (w == -1 && errno != EINTR) - break; - } -#endif - - if (w == -1) - { - rc = -1; - rerrno = errno; - } -#ifndef VMS /* status is return status */ - else if (WIFEXITED (status)) - rc = WEXITSTATUS (status); - else if (WIFSIGNALED (status)) - { - if (WTERMSIG (status) == SIGPIPE) - error (1, 0, "broken pipe"); - rc = 2; - } - else - rc = 1; -#else /* VMS */ - rc = WEXITSTATUS (status); -#endif /* VMS */ - - /* restore the signals */ -#ifdef POSIX_SIGNALS - if (flags & RUN_SIGIGNORE) - { - (void) sigaction (SIGINT, &iact, (struct sigaction *)NULL); - (void) sigaction (SIGQUIT, &qact, (struct sigaction *)NULL); - } - else - (void) sigprocmask (SIG_SETMASK, &sigset_omask, (sigset_t *)NULL); -#else -#ifdef BSD_SIGNALS - if (flags & RUN_SIGIGNORE) - { - (void) sigvec (SIGINT, &ivec, (struct sigvec *)NULL); - (void) sigvec (SIGQUIT, &qvec, (struct sigvec *)NULL); - } - else - (void) sigsetmask (mask); -#else - (void) signal (SIGINT, istat); - (void) signal (SIGQUIT, qstat); -#endif -#endif - - /* cleanup the open file descriptors */ - out: - if (sterr) - (void) close (sherr); - else - /* ensure things are received by the parent in the correct order - * relative to the protocol pipe - */ - cvs_flusherr(); - out2: - if (stout) - (void) close (shout); - else - /* ensure things are received by the parent in the correct order - * relative to the protocol pipe - */ - cvs_flushout(); - out1: - if (stin) - (void) close (shin); - - out0: - if (rerrno) - errno = rerrno; - return rc; -} - - - -void -run_print (fp) - FILE *fp; -{ - int i; - void (*outfn) PROTO ((const char *, size_t)); - - if (fp == stderr) - outfn = cvs_outerr; - else if (fp == stdout) - outfn = cvs_output; - else - { - error (1, 0, "internal error: bad argument to run_print"); - /* Solely to placate gcc -Wall. - FIXME: it'd be better to use a function named `fatal' that - is known never to return. Then kludges wouldn't be necessary. */ - outfn = NULL; - } - - for (i = 0; i < run_argc; i++) - { - (*outfn) ("'", 1); - (*outfn) (run_argv[i], 0); - (*outfn) ("'", 1); - if (i != run_argc - 1) - (*outfn) (" ", 1); - } -} - -/* Return value is NULL for error, or if noexec was set. If there was an - error, return NULL and I'm not sure whether errno was set (the Red Hat - Linux 4.1 popen manpage was kind of vague but discouraging; and the noexec - case complicates this even aside from popen behavior). */ - -FILE * -run_popen (cmd, mode) - const char *cmd; - const char *mode; -{ - if (trace) - (void) fprintf (stderr, "%s-> run_popen(%s,%s)\n", - CLIENT_SERVER_STR, cmd, mode); - if (noexec) - return (NULL); - - return (popen (cmd, mode)); -} - - - -/* Work around an OpenSSH problem: it can put its standard file - descriptors into nonblocking mode, which will mess us up if we - share file descriptions with it. The simplest workaround is - to create an intervening process between OpenSSH and the - actual stderr. */ - -static void -work_around_openssh_glitch (void) -{ - pid_t pid; - int stderr_pipe[2]; - struct stat sb; - - /* Do nothing unless stderr is a file that is affected by - nonblocking mode. */ - if (!(fstat (STDERR_FILENO, &sb) == 0 - && (S_ISFIFO (sb.st_mode) || S_ISSOCK (sb.st_mode) - || S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode)))) - return; - - if (pipe (stderr_pipe) < 0) - error (1, errno, "cannot create pipe"); - pid = fork (); - if (pid < 0) - error (1, errno, "cannot fork"); - if (pid != 0) - { - /* Still in child of original process. Act like "cat -u". */ - char buf[1 << 13]; - ssize_t inbytes; - pid_t w; - int status; - - if (close (stderr_pipe[1]) < 0) - error (1, errno, "cannot close pipe"); - - while ((inbytes = read (stderr_pipe[0], buf, sizeof buf)) != 0) - { - size_t outbytes = 0; - - if (inbytes < 0) - { - if (errno == EINTR) - continue; - error (1, errno, "reading from pipe"); - } - - do - { - ssize_t w = write (STDERR_FILENO, - buf + outbytes, inbytes - outbytes); - if (w < 0) - { - if (errno == EINTR) - w = 0; - if (w < 0) - _exit (1); - } - outbytes += w; - } - while (inbytes != outbytes); - } - - /* Done processing output from grandchild. Propagate - its exit status back to the parent. */ - while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR) - continue; - if (w < 0) - error (1, errno, "waiting for child"); - if (!WIFEXITED (status)) - { - if (WIFSIGNALED (status)) - raise (WTERMSIG (status)); - error (1, errno, "child did not exit cleanly"); - } - _exit (WEXITSTATUS (status)); - } - - /* Grandchild of original process. */ - if (close (stderr_pipe[0]) < 0) - error (1, errno, "cannot close pipe"); - - if (stderr_pipe[1] != STDERR_FILENO) - { - if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0) - error (1, errno, "cannot dup2 pipe"); - if (close (stderr_pipe[1]) < 0) - error (1, errno, "cannot close pipe"); - } -} - - - -int -piped_child (command, tofdp, fromfdp, fix_stderr) - const char **command; - int *tofdp; - int *fromfdp; - int fix_stderr; -{ - int pid; - int to_child_pipe[2]; - int from_child_pipe[2]; - - if (pipe (to_child_pipe) < 0) - error (1, errno, "cannot create pipe"); - if (pipe (from_child_pipe) < 0) - error (1, errno, "cannot create pipe"); - -#ifdef USE_SETMODE_BINARY - setmode (to_child_pipe[0], O_BINARY); - setmode (to_child_pipe[1], O_BINARY); - setmode (from_child_pipe[0], O_BINARY); - setmode (from_child_pipe[1], O_BINARY); -#endif - - pid = fork (); - if (pid < 0) - error (1, errno, "cannot fork"); - if (pid == 0) - { - if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0) - error (1, errno, "cannot dup2 pipe"); - if (close (to_child_pipe[1]) < 0) - error (1, errno, "cannot close pipe"); - if (close (from_child_pipe[0]) < 0) - error (1, errno, "cannot close pipe"); - if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0) - error (1, errno, "cannot dup2 pipe"); - - if (fix_stderr) - work_around_openssh_glitch (); - - /* Okay to cast out const below - execvp don't return nohow. */ - execvp ((char *)command[0], (char **)command); - error (1, errno, "cannot exec %s", command[0]); - } - if (close (to_child_pipe[0]) < 0) - error (1, errno, "cannot close pipe"); - if (close (from_child_pipe[1]) < 0) - error (1, errno, "cannot close pipe"); - - *tofdp = to_child_pipe[1]; - *fromfdp = from_child_pipe[0]; - return pid; -} - - -void -close_on_exec (fd) - int fd; -{ -#ifdef F_SETFD - if (fcntl (fd, F_SETFD, 1) == -1) - error (1, errno, "can't set close-on-exec flag on %d", fd); -#endif -} diff --git a/contrib/cvs/src/sanity.sh b/contrib/cvs/src/sanity.sh deleted file mode 100755 index dbcae19..0000000 --- a/contrib/cvs/src/sanity.sh +++ /dev/null @@ -1,30254 +0,0 @@ -#! /bin/sh -: -# sanity.sh -- a growing testsuite for cvs. -# -# The copyright notice said: "Copyright (C) 1992, 1993 Cygnus Support" -# I'm not adding new copyright notices for new years as our recent -# practice has been to include copying terms without copyright notices. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# Original Author: K. Richard Pixley - -# usage: -usage () -{ - echo "Usage: `basename $0` --help" - echo "Usage: `basename $0` [-eklrv] [-f FROM-TEST] [-h HOSTNAME] CVS-TO-TEST [TESTS-TO-RUN...]" -} - -exit_usage () -{ - usage 1>&2 - exit 2 -} - -exit_help () -{ - usage - echo - echo "-H|--help Display this text." - echo "-e|--skipfail Treat tests that would otherwise be nonfatally skipped" - echo " for reasons like missing tools as failures, exiting" - echo " with an error message. Also treat warnings as" - echo " failures." - echo "-f FROM-TEST Run TESTS-TO-RUN, skipping all tests in the list before" - echo " FROM-TEST." - echo "-h HOSTNAME Use :ext:HOSTNAME to run remote tests rather than" - echo " :fork:. Implies --remote and assumes that \$TESTDIR" - echo " resolves to the same directory on both the client and" - echo " the server." - echo "-k|--keep Try to keep directories created by individual tests" - echo " around, exiting after the first test which supports" - echo " --keep." - echo "-l|--link-root" - echo " Test CVS using a symlink to a real CVSROOT." - echo "-r|--remote Test remote instead of local cvs." - echo "-v|--verbose List test names as they are executed." - echo - echo "CVS-TO-TEST The path to the CVS executable to be tested." - echo "TESTS-TO-RUN The names of the tests to run (defaults to all tests)." - exit 2 -} - -# See TODO list at end of file. - -# required to make this script work properly. -unset CVSREAD - -# This will cause malloc to run slower but should also catch some common errors -# when CVS is linked with glibc 2.x. -MALLOC_CHECK_=2; export MALLOC_CHECK_ - -# We want to invoke a predictable set of i18n behaviors, not whatever -# the user running this script might have set. -# In particular: -# 'sort' and tabs and spaces (LC_COLLATE). -# Messages from getopt (LC_MESSAGES) (in the future, CVS itself might -# also alter its messages based on LC_MESSAGES). -LANG=C -export LANG -LC_ALL=C -export LC_ALL - - -# -# Initialize the test counts. -# -passed=0 -skipped=0 -warnings=0 - - - -# -# read our options -# -unset fromtest -unset remotehost -keep=false -linkroot=false -remote=false -skipfail=false -verbose=false -while getopts ef:h:Hklrv-: option ; do - # convert the long opts to short opts - if test x$option = x-; then - case "$OPTARG" in - [hH]|[hH][eE]|[hH][eE][lL]|[hH][eE][lL][pP]) - option=H; - OPTARG= - ;; - [kK]|[kK][eE]|[kK][eE][eE]|[kK][eE][eE][pP]) - option=k; - OPTARG= - ;; - l|li|lin|link|link-|link-r]|link-ro|link-roo|link-root) - option=l; - OPTARG= - ;; - [rR]|[rR][eE]|[rR][eE][mM]|[rR][eE][mM][oO]|[rR][eE][mM][oO][tT]|[rR][eE][mM][oO][tT][eE]) - option=k; - OPTARG= - ;; - s|sk|ski|skip|skipf|skipfa|skipfai|skipfail) - option=e - OPTARG= - ;; - v|ve|ver|verb|verbo|verbos|verbose) - option=v - OPTARG= - ;; - *) - option=\? - OPTARG= - esac - fi - case "$option" in - e) - skipfail=: - ;; - f) - fromtest="$OPTARG" - ;; - h) - # Set a remotehost to run the remote tests on via :ext: - # Implies `-r' and assumes that $TESTDIR resolves to the same - # directory on the client and the server. - remotehost="$OPTARG" - remote=: - ;; - H) - exit_help - ;; - k) - # The -k (keep) option will eventually cause all the tests to - # leave around the contents of the /tmp directory; right now only - # some implement it. Not originally intended to be useful with - # more than one test, but this should work if each test uses a - # uniquely named dir (use the name of the test). - keep=: - ;; - l) - linkroot=: - ;; - r) - remote=: - ;; - v) - verbose=: - ;; - \?) - exit_usage - ;; - esac -done - -# boot the arguments we used above -while test $OPTIND -gt 1 ; do - shift - OPTIND=`expr $OPTIND - 1` -done - -# Use full path for CVS executable, so that CVS_SERVER gets set properly -# for remote. -case $1 in -"") - exit_usage - ;; -/*) - testcvs=$1 - ;; -*) - testcvs=`pwd`/$1 - ;; -esac -shift - -# If $remotehost is set, warn if $TESTDIR isn't since we are pretty sure -# that its default value of `/tmp/cvs-sanity' will not resolve to the same -# directory on two different machines. -if test -n "$remotehost" && test -z "$TESTDIR"; then - echo "WARNING: CVS server hostname is set and \$TESTDIR is not. If" >&2 - echo "$remotehost is not the local machine, then it is unlikely that" >&2 - echo "the default value assigned to \$TESTDIR will resolve to the same" >&2 - echo "directory on both this client and the CVS server." >&2 -fi - - - -### -### GUTS -### - -# "debugger" -#set -x - -echo 'This test should produce no other output than this message, and a final "OK".' -echo '(Note that the test can take an hour or more to run and periodically stops' -echo 'for as long as one minute. Do not assume there is a problem just because' -echo 'nothing seems to happen for a long time. If you cannot live without' -echo 'running status, use the -v option or try the command:' -echo "\`tail -f check.log' from another window.)" - -# Regexp to match what CVS will call itself in output that it prints. -# FIXME: we don't properly quote this--if the name contains . we'll -# just spuriously match a few things; if the name contains other regexp -# special characters we are probably in big trouble. -PROG=`basename ${testcvs}` - -# Match the hostname -hostname="[-_.a-zA-Z0-9]*" - -# Regexp to match the name of a temporary file (from cvs_temp_name). -# This appears in certain diff output. -tempname="[-a-zA-Z0-9/.%_]*" - -# Regexp to match a date in RFC822 format (as amended by RFC1123). -RFCDATE="[a-zA-Z0-9 ][a-zA-Z0-9 ]* [0-9:][0-9:]* -0000" -RFCDATE_EPOCH="1 Jan 1970 00:00:00 -0000" - -# Regexp to match a date in standard Unix format as used by rdiff -# FIXCVS: There's no reason for rdiff to use a different date format -# than diff does -DATE="[a-zA-Z]* [a-zA-Z]* [ 1-3][0-9] [0-9:]* [0-9]*" - -# Which directories should Which and find_tool search for executables? -SEARCHPATH=$PATH:/usr/local/bin:/usr/contrib/bin:/usr/contrib:/usr/gnu/bin:/local/bin:/local/gnu/bin:/gnu/bin:/sw/bin:/usr/pkg/bin - -# Do not assume that `type -p cmd` is portable -# Usage: Which [-a] [-x|-f|-r] prog [$SEARCHPATH:/with/directories:/to/search] -Which() { - # Optional first argument for file type, defaults to -x. - # Second argument is the file or directory to be found. - # Third argument is the PATH to search. - # By default, print only the first file that matches, - # -a will cause all matches to be printed. - notevery=: - if [ "x$1" = "x-a" ]; then notevery=false; shift; fi - case "$1" in - -*) t=$1; shift ;; - *) t=-x ;; - esac - case "$1" in - # FIXME: Someday this may need to be fixed - # to deal better with C:\some\path\to\ssh values... - /*) test $t $1 && echo $1 ;; - *) for d in `IFS=:; echo ${2-$SEARCHPATH}` - do - test $t $d/$1 && { echo $d/$1; if $notevery; then break; fi; } - done - ;; - esac -} - - -# On cygwin32, we may not have /bin/sh. -if test -r /bin/sh; then - TESTSHELL="/bin/sh" -else - TESTSHELL=`Which -f sh` - if test ! -r "$TESTSHELL"; then - TESTSHELL="/bin/sh" - fi -fi - -# FIXME: try things (what things? checkins?) without -m. -# -# Some of these tests are written to expect -Q. But testing with -# -Q is kind of bogus, it is not the way users actually use CVS (usually). -# So new tests probably should invoke ${testcvs} directly, rather than ${CVS}. -# and then they've obviously got to do something with the output.... -# -CVS="${testcvs} -Q" - -LOGFILE=`pwd`/check.log - -# Save the previous log in case the person running the tests decides -# they want to look at it. The extension ".plog" is chosen for consistency -# with dejagnu. -if test -f check.log; then - mv check.log check.plog -fi - -# Create the log file so check.log can be tailed almost immediately after -# this script is started. Otherwise it can take up to a minute or two before -# the log file gets created when $remotehost is specified on some systems, -# which makes for a lot of failed `tail -f' attempts. -touch check.log - -# Workaround any X11Forwarding by ssh. Otherwise this text: -# Warning: No xauth data; using fake authentication data for X11 forwarding. -# has been known to end up in the test results below -# causing the test to fail. -[ -n "$DISPLAY" ] && unset DISPLAY - -# The default value of /tmp/cvs-sanity for TESTDIR is dubious, -# because it loses if two people/scripts try to run the tests -# at the same time. Some possible solutions: -# 1. Use /tmp/cvs-test$$. One disadvantage is that the old -# cvs-test* directories would pile up, because they wouldn't -# necessarily get removed. -# 2. Have everyone/everything running the testsuite set -# TESTDIR to some appropriate directory. -# 3. Have the default value of TESTDIR be some variation of -# `pwd`/cvs-sanity. The biggest problem here is that we have -# been fairly careful to test that CVS prints in messages the -# actual pathnames that we pass to it, rather than a different -# pathname for the same directory, as may come out of `pwd`. -# 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. -: ${CVS_RSH=rsh}; export CVS_RSH -if test -n "$remotehost"; then - # We need to set $tmp on the server since $TMPDIR is compared against - # messages generated by the server. - tmp=`$CVS_RSH $remotehost 'cd /tmp; /bin/pwd || pwd' 2>/dev/null` - if test $? != 0; then - echo "$CVS_RSH $remotehost failed." >&2 - exit 1 - fi -else - tmp=`(cd /tmp; /bin/pwd || pwd) 2>/dev/null` -fi - -# Now: -# 1) Set TESTDIR if it's not set already -# 2) Remove any old test remnants -# 3) Create $TESTDIR -# 4) Normalize TESTDIR with `cd && (/bin/pwd || pwd)` -# (This will match CVS output later) -: ${TESTDIR=$tmp/cvs-sanity} -# 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 -# These exits are important. The first time I tried this, if the `mkdir && cd` -# failed then the build directory would get blown away. Some people probably -# wouldn't appreciate that. -mkdir ${TESTDIR} || exit 1 -cd ${TESTDIR} || exit 1 -# Ensure $TESTDIR is absolute -if echo "${TESTDIR}" |grep '^[^/]'; then - # Don't resolve this unless we have to. This keeps symlinks intact. This - # is important at least when testing using -h $remotehost, because the same - # value for $TESTDIR must resolve to the same directory on the client and - # the server and we likely used Samba, and possibly symlinks, to do this. - TESTDIR=`(/bin/pwd || pwd) 2>/dev/null` -fi - -if test -z "${TESTDIR}" || echo "${TESTDIR}" |grep '^[^/]'; then - echo "Unable to resolve TESTDIR to an absolute directory." >&2 - exit 1 -fi -cd ${TESTDIR} - -# Now set $TMPDIR if the user hasn't overridden it. -# -# We use a $TMPDIR under $TESTDIR by default so that two tests may be run at -# the same time without bumping heads without requiring the user to specify -# more than $TESTDIR. See the test for leftover cvs-serv* directories near the -# end of this script at the end of "The big loop". -: ${TMPDIR=$TESTDIR/tmp} -export TMPDIR -if test -d $TMPDIR; then :; else - mkdir $TMPDIR -fi - -# Make sure various tools work the way we expect, or try to find -# versions that do. -: ${AWK=awk} -: ${EXPR=expr} -: ${ID=id} -: ${TR=tr} - -# Keep track of tools that are found, but do NOT work as we hope -# in order to avoid them in future -badtools= -set_bad_tool () -{ - badtools=$badtools:$1 -} -is_bad_tool () -{ - case ":$badtools:" in *:$1:*) return 0 ;; *) return 1 ; esac -} - -version_test () -{ - vercmd=$1 - verbad=: - if RES=`$vercmd --version </dev/null 2>&1`; then - if test "X$RES" != "X--version" && test "X$RES" != "X" ; then - echo "$RES" - verbad=false - fi - fi - if $verbad; then - echo "The command \`$vercmd' does not support the --version option." - fi - # It does not really matter that --version is not supported - return 0 -} - -# Try to find a tool that satisfies all of the tests. -# Usage: list:of:colon:separated:alternatives test1 test2 test3 test4... -# Example: find_tool awk:gawk:nawk awk_tooltest1 awk_tooltest2 -find_tool () -{ - default_TOOL=$1 - echo find_tool: ${1+"$@"} >>$LOGFILE - cmds="`IFS=:; echo $1`"; shift; tooltests="${1+$@}" - if test -z "$tooltests"; then tooltests=version_test; fi - clist=; for cmd in $cmds; do clist="$clist `Which -a $cmd`"; done - # Make sure the default tool is just the first real command name - for default_TOOL in $clist `IFS=:; echo $default_TOOL`; do break; done - TOOL="" - for trytool in $clist ; do - pass=: - for tooltest in $tooltests; do - result=`eval $tooltest $trytool` - rc=$? - echo "Running $tooltest $trytool" >>$LOGFILE - if test -n "$result"; then - echo "$result" >>$LOGFILE - fi - if test "$rc" = "0"; then - echo "PASS: $tooltest $trytool" >>$LOGFILE - elif test "$rc" = "77"; then - echo "MARGINAL: $tooltest $trytool; rc=$rc" >>$LOGFILE - TOOL=$trytool - pass=false - else - set_bad_tool $trytool - echo "FAIL: $tooltest $trytool; rc=$rc" >>$LOGFILE - pass=false - fi - done - if $pass; then - echo $trytool - return 0 - fi - done - if test -n "$TOOL"; then - echo "Notice: The default version of \`$default_TOOL' is defective." >>$LOGFILE - echo "using \`$TOOL' and hoping for the best." >>$LOGFILE - echo "Notice: The default version of \`$default_TOOL' is defective." >&2 - echo "using \`$TOOL' and hoping for the best." >&2 - echo $TOOL - else - echo $default_TOOL - fi -} - -id_tool_test () -{ - id=$1 - if $id -u >/dev/null 2>&1 && $id -un >/dev/null 2>&1; then - return 0 - else - echo "Running these tests requires an \`id' program that understands the" - echo "-u and -n flags. Make sure that such an id (GNU, or many but not" - echo "all vendor-supplied versions) is in your path." - return 1 - fi -} - -ID=`find_tool id version_test id_tool_test` -echo "Using ID=$ID" >>$LOGFILE - -# You can't run CVS as root; print a nice error message here instead -# of somewhere later, after making a mess. -for pass in false :; do - case "`$ID -u 2>/dev/null`" in - "0") - echo "Test suite does not work correctly when run as root" >&2 - exit 1 - ;; - - *) - break - ;; - esac -done - -# Cause NextStep 3.3 users to lose in a more graceful fashion. -expr_tooltest1 () -{ -expr=$1 -if $expr 'abc -def' : 'abc -def' >/dev/null; then - # good, it works - return 0 -else - 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.' - return 1 -fi -} - -# Warn SunOS, SysVr3.2, etc., users that they may be partially losing -# if we can't find a GNU expr to ease their troubles... -expr_tooltest2 () -{ -expr=$1 -if $expr 'a -b' : 'a -c' >/dev/null; then - echo 'WARNING: you are using a version of expr that does not correctly' - echo 'match multi-line patterns. Some tests may spuriously pass or fail.' - echo 'You may wish to make sure GNU expr is in your path.' - return 1 -else - return 0 -fi -} - -expr_create_bar () -{ -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 -rm -f ${TESTDIR}/foo -} - -expr_tooltest3 () -{ -expr=$1 -# More SunOS lossage... -test ! -f ${TESTDIR}/bar && expr_create_bar -if $expr "`cat ${TESTDIR}/bar`" : "`cat ${TESTDIR}/bar`" >/dev/null; then - : good, it works -else - echo 'WARNING: you are using a version of expr that does not correctly' - echo 'match large patterns. Some tests may spuriously pass or fail.' - echo 'You may wish to make sure GNU expr is in your path.' - return 1 -fi -if $expr "`cat ${TESTDIR}/bar`x" : "`cat ${TESTDIR}/bar`y" >/dev/null; then - echo 'WARNING: you are using a version of expr that does not correctly' - echo 'match large patterns. Some tests may spuriously pass or fail.' - echo 'You may wish to make sure GNU expr is in your path.' - return 1 -fi -# good, it works -return 0 -} - -# 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 -# next release of GNU expr after 1.12 (but we still have to cater to the old -# ones for some time because they are in many linux distributions). -ENDANCHOR="$" -expr_set_ENDANCHOR () -{ -expr=$1 -ENDANCHOR="$" -if $expr 'abc -def' : 'abc$' >/dev/null; then - ENDANCHOR='\'\' - echo "Notice: An ENDANCHOR of dollar does not work." - echo "Using a workaround for GNU expr versions 1.9.4 thru 1.12" -fi -return 0 -} - -# Work around another GNU expr (version 1.10-1.12) bug/incompatibility. -# "." doesn't appear to match a newline (it does with SunOS 4.1.3 expr). -# Note that the workaround is not a complete equivalent of .* because -# the first parenthesized expression in the regexp must match something -# in order for expr to return a successful exit status. -# Rumor has it this will be fixed in the -# next release of GNU expr after 1.12 (but we still have to cater to the old -# ones for some time because they are in many linux distributions). -DOTSTAR='.*' -expr_set_DOTSTAR () -{ -expr=$1 -DOTSTAR='.*' -if $expr 'abc -def' : "a${DOTSTAR}f" >/dev/null; then - : good, it works -else - DOTSTAR='\(.\| -\)*' - echo "Notice: DOTSTAR changed from sane \`.*' value to \`$DOTSTAR\`" - echo "to workaround GNU expr version 1.10 thru 1.12 bug where \`.'" - echo "does not match a newline." -fi -return 0 -} - -# Now that we have DOTSTAR, make sure it works with big matches -expr_tooltest_DOTSTAR () -{ -expr=$1 -test ! -f ${TESTDIR}/bar && expr_create_bar -if $expr "`cat ${TESTDIR}/bar`" : "${DOTSTAR}xyzABC${DOTSTAR}$" >/dev/null; then - # good, it works - return 0 -else - echo 'WARNING: you are using a version of expr that does not correctly' - echo 'match large patterns. Some tests may spuriously pass or fail.' - echo 'You may wish to make sure GNU expr is in your path.' - return 77 -fi -} - -# FreeBSD 5.2 and 6.1 support 'expr [-e] expression' -# They get confused unless '--' is used before the expressions -# when those expressions begin with a '-' character, such as the -# output of an ls -l command. The EXPR_COMPAT environment variable may -# be used to go back to the non-POSIX behavior as an alternative. -# (GNU expr appears to accept the '--' argument and work correctly or -# not have it and still get the results we want.) -exprDASHDASH='false' -expr_set_DASHDASH () -{ -expr=$1 -exprDASHDASH='false' -# Not POSIX, but works on a lot of expr versions. -if $expr "-rw-rw-r--" : "-rw-rw-r--" >/dev/null 2>&1; then - # good, it works - return 0 -else - # Do things in the POSIX manner. - if $expr -- "-rw-rw-r--" : "-rw-rw-r--" >/dev/null 2>&1; then - exprDASHDASH=':' - return 0 - else - echo 'WARNING: Your $expr does not correctly handle' - echo 'leading "-" characters in regular expressions to' - echo 'be matched. You may wish to see if there is an' - echo 'environment variable or other setting to allow' - echo 'POSIX functionality to be enabled.' - return 77 - fi -fi -} - - -EXPR=`find_tool ${EXPR}:gexpr \ - version_test expr_tooltest1 expr_tooltest2 expr_tooltest3 \ -expr_set_ENDANCHOR expr_set_DOTSTAR expr_tooltest_DOTSTAR` - -# Set the ENDANCHOR and DOTSTAR for the chosen expr version. -expr_set_ENDANCHOR ${EXPR} >/dev/null -expr_tooltest_DOTSTAR ${EXPR} >/dev/null - -# Is $EXPR a POSIX or non-POSIX implementation -# with regard to command-line arguments? -expr_set_DASHDASH ${EXPR} -$exprDASHDASH && EXPR="$EXPR --" - -echo "Using EXPR=$EXPR" >>$LOGFILE -echo "Using ENDANCHOR=$ENDANCHOR" >>$LOGFILE -echo "Using DOTSTAR=$DOTSTAR" >>$LOGFILE - -# Cleanup -rm -f ${TESTDIR}/bar - -# Work around yet another GNU expr (version 1.10) bug/incompatibility. -# "+" is a special character, yet for unix expr (e.g. SunOS 4.1.3) -# it is not. I doubt that POSIX allows us to use \+ and assume it means -# (non-special) +, so here is another workaround -# Rumor has it this will be fixed in the -# next release of GNU expr after 1.12 (but we still have to cater to the old -# ones for some time because they are in many linux distributions). -PLUS='+' -if $EXPR 'a +b' : "a ${PLUS}b" >/dev/null; then - : good, it works -else - PLUS='\+' -fi - -# Likewise, for ? -QUESTION='?' -if $EXPR 'a?b' : "a${QUESTION}b" >/dev/null; then - : good, it works -else - QUESTION='\?' -fi - -# Now test the username to make sure it contains only valid characters -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 - -# Only 8 characters of $username appear in some output. -if test `echo $username |wc -c` -gt 8; then - username8=`echo $username |sed 's/^\(........\).*/\1/'` -else - username8=$username -fi - -# Rarely, we need to match any username, not just the name of the user -# running this test. -# -# I'm not really sure what characters should be here. a-zA-Z obviously. -# People complained when 0-9 were not allowed in usernames. Other than that -# I'm not sure. -anyusername="[-a-zA-Z0-9][-a-zA-Z0-9]*" - -# now make sure that tr works on NULs -tr_tooltest1 () -{ -tr=$1 -if $EXPR `echo "123" | $tr '2' '\0'` : "123" >/dev/null 2>&1; 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.' - return 77 -fi -# good, it works -return 0 -} - -TR=`find_tool ${TR}:gtr version_test tr_tooltest1` -echo "Using TR=$TR" >>$LOGFILE - -# Awk testing - -awk_tooltest1 () -{ -awk=$1 -$awk 'BEGIN {printf("one\ntwo\nthree\nfour\nfive\nsix")}' </dev/null >abc -if $EXPR "`cat abc`" : \ -'one -two -three -four -five -six'; then - rm abc - return 0 -else - rm abc - echo "Notice: awk BEGIN clause or printf is not be working properly." - return 1 -fi -} - -# Format item %c check -awk_tooltest2 () -{ -awk=$1 -$awk 'BEGIN { printf "%c%c%c", 2, 3, 4 }' </dev/null \ - | ${TR} '\002\003\004' '123' >abc -if $EXPR "`cat abc`" : "123" ; then - : good, found it -else - echo "Notice: awk format %c string may not be working properly." - rm abc - return 77 -fi -rm abc -return 0 -} - -AWK=`find_tool gawk:nawk:awk version_test awk_tooltest1 awk_tooltest2` -echo "Using AWK=$AWK" >>$LOGFILE - -# Test that $1 works as a remote shell. If so, set $host, $CVS_RSH, & -# $save_CVS_RSH to match and return 0. Otherwise, set $skipreason and return -# 77. -depends_on_rsh () -{ - host=${remotehost-"`hostname`"} - result=`$1 $host 'echo test'` - rc=$? - if test $? != 0 || test "x$result" != "xtest"; then - skipreason="\`$1 $host' failed rc=$rc result=$result" - return 77 - fi - - save_CVS_RSH=$CVS_RSH - CVS_RSH=$1; export CVS_RSH - return 0 -} - -# Find a usable SSH. When a usable ssh is found, set $host, $CVS_RSH, and -# $save_CVS_RSH and return 0. Otherwise, set $skipreason and return 77. -depends_on_ssh () -{ - case "$CVS_RSH" in - *ssh*|*putty*) - tryssh=`Which $CVS_RSH` - if [ ! -n "$tryssh" ]; then - skipreason="Unable to find CVS_RSH=$CVS_RSH executable" - return 77 - elif [ ! -x "$tryssh" ]; then - skipreason="Unable to execute $tryssh program" - return 77 - fi - ;; - *) - # Look in the user's PATH for "ssh" - tryssh=`Which ssh` - if test ! -r "$tryssh"; then - skipreason="Unable to find ssh program" - return 77 - fi - ;; - esac - - depends_on_rsh "$tryssh" - return $? -} - -pass () -{ - echo "PASS: $1" >>${LOGFILE} - passed=`expr $passed + 1` -} - -# Like skip(), but don't fail when $skipfail is set. -skip_always () -{ - echo "SKIP: $1${2+ ($2)}" >>$LOGFILE - skipped=`expr $skipped + 1` -} - -skip () -{ - if $skipfail; then - fail "$1${2+ ($2)}" - else - echo "SKIP: $1${2+ ($2)}" >>$LOGFILE - fi - skipped=`expr $skipped + 1` -} - -warn () -{ - if $skipfail; then - fail "$1${2+ ($2)}" - else - echo "WARNING: $1${2+ ($2)}" >>$LOGFILE - fi - warnings=`expr $warnings + 1` -} - -# Convenience function for skipping tests run only in local mode. -localonly () -{ - skip_always $1 "only tested in local mode" -} - -fail () -{ - echo "FAIL: $1" | tee -a ${LOGFILE} - echo "*** Please see the \`TESTS' and \`check.log' files for more information." >&2 - # This way the tester can go and see what remnants were left - exit 1 -} - -verify_tmp_empty () -{ - # Test our temp directory for cvs-serv* directories and cvsXXXXXX temp - # files. We would like to not leave any behind. - if $remote && ls $TMPDIR/cvs-serv* >/dev/null 2>&1; then - # A true value means ls found files/directories with these names. - # Give the server some time to finish, then retry. - sleep 1 - if ls $TMPDIR/cvs-serv* >/dev/null 2>&1; then - warn "$1" "Found cvs-serv* directories in $TMPDIR." - # The above will exit if $skipfail - rm -rf $TMPDIR/cvs-serv* - fi - fi - if ls $TMPDIR/cvs?????? >/dev/null 2>&1; then - # A true value means ls found files/directories with these names. - warn "$1" "Found cvsXXXXXX temp files in $TMPDIR." - # The above will exit if $skipfail - rm -f ls $TMPDIR/cvs?????? - fi -} - -# Restore changes to CVSROOT admin files. -restore_adm () -{ - rm -rf $CVSROOT_DIRNAME/CVSROOT - cp -Rp $TESTDIR/CVSROOT.save $CVSROOT_DIRNAME/CVSROOT -} - -# See dotest and dotest_fail for explanation (this is the parts -# of the implementation common to the two). -dotest_internal () -{ - if $EXPR "`cat ${TESTDIR}/dotest.tmp`" : "$3${ENDANCHOR}" >/dev/null; then - # Why, I hear you ask, do we write this to the logfile - # even when the test passes? The reason is that the test - # may give us the regexp which we were supposed to match, - # but sometimes it may be useful to look at the exact - # text which was output. For example, suppose one wants - # to grep for a particular warning, and make _sure_ that - # CVS never hits it (even in cases where the tests might - # match it with .*). Or suppose one wants to see the exact - # date format output in a certain case (where the test will - # surely use a somewhat non-specific pattern). - cat ${TESTDIR}/dotest.tmp >>${LOGFILE} - pass "$1" - verify_tmp_empty "$1" - # expr can't distinguish between "zero characters matched" and "no match", - # so special-case it. - elif test -z "$3" && test ! -s ${TESTDIR}/dotest.tmp; then - pass "$1" - verify_tmp_empty "$1" - elif test x"$4" != x; then - if $EXPR "`cat ${TESTDIR}/dotest.tmp`" : "$4${ENDANCHOR}" >/dev/null; then - cat ${TESTDIR}/dotest.tmp >>${LOGFILE} - pass "$1" - verify_tmp_empty "$1" - else - echo "** expected: " >>${LOGFILE} - echo "$3" >>${LOGFILE} - echo "$3" > ${TESTDIR}/dotest.ex1 - echo "** or: " >>${LOGFILE} - echo "$4" >>${LOGFILE} - echo "$4" > ${TESTDIR}/dotest.ex2 - echo "** got: " >>${LOGFILE} - cat ${TESTDIR}/dotest.tmp >>${LOGFILE} - fail "$1" - fi - else - echo "** expected: " >>${LOGFILE} - echo "$3" >>${LOGFILE} - echo "$3" > ${TESTDIR}/dotest.exp - echo "** got: " >>${LOGFILE} - cat ${TESTDIR}/dotest.tmp >>${LOGFILE} - fail "$1" - fi -} - -dotest_all_in_one () -{ - if $EXPR "`cat ${TESTDIR}/dotest.tmp`" : \ - "`cat ${TESTDIR}/dotest.exp`" >/dev/null; then - return 0 - fi - return 1 -} - -# WARNING: this won't work with REs that match newlines.... -# -dotest_line_by_line () -{ - line=1 - 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 - : - elif test -z "`sed -n ${line}p ${TESTDIR}/dotest.tmp`" && - test -z "`sed -n ${line}p ${TESTDIR}/dotest.exp`"; then - : - else - echo "Line $line:" >> ${LOGFILE} - echo "**** expected: " >>${LOGFILE} - sed -n ${line}p ${TESTDIR}/dotest.exp >>${LOGFILE} - echo "**** got: " >>${LOGFILE} - sed -n ${line}p ${TESTDIR}/dotest.tmp >>${LOGFILE} - unset line - return 1 - fi - line=`expr $line + 1` - done - unset line - return 0 -} - -# If you are having trouble telling which line of a multi-line -# expression is not being matched, replace calls to dotest_internal() -# with calls to this function: -# -dotest_internal_debug () -{ - if test -z "$3"; then - if test -s ${TESTDIR}/dotest.tmp; then - echo "** expected: " >>${LOGFILE} - echo "$3" >>${LOGFILE} - echo "$3" > ${TESTDIR}/dotest.exp - rm -f ${TESTDIR}/dotest.ex2 - echo "** got: " >>${LOGFILE} - cat ${TESTDIR}/dotest.tmp >>${LOGFILE} - fail "$1" - else - pass "$1" - verify_tmp_empty "$1" - fi - else - echo "$3" > ${TESTDIR}/dotest.exp - if dotest_line_by_line "$1" "$2"; then - pass "$1" - verify_tmp_empty "$1" - else - if test x"$4" != x; then - mv ${TESTDIR}/dotest.exp ${TESTDIR}/dotest.ex1 - echo "$4" > ${TESTDIR}/dotest.exp - if dotest_line_by_line "$1" "$2"; then - pass "$1" - verify_tmp_empty "$1" - else - mv ${TESTDIR}/dotest.exp ${TESTDIR}/dotest.ex2 - echo "** expected: " >>${LOGFILE} - echo "$3" >>${LOGFILE} - echo "** or: " >>${LOGFILE} - echo "$4" >>${LOGFILE} - echo "** got: " >>${LOGFILE} - cat ${TESTDIR}/dotest.tmp >>${LOGFILE} - fail "$1" - fi - else - echo "** expected: " >>${LOGFILE} - echo "$3" >>${LOGFILE} - echo "** got: " >>${LOGFILE} - cat ${TESTDIR}/dotest.tmp >>${LOGFILE} - fail "$1" - fi - fi - fi -} - -# Usage: -# dotest TESTNAME COMMAND OUTPUT [OUTPUT2] -# TESTNAME is the name used in the log to identify the test. -# COMMAND is the command to run; for the test to pass, it exits with -# exitstatus zero. -# OUTPUT is a regexp which is compared against the output (stdout and -# stderr combined) from the test. It is anchored to the start and end -# of the output, so should start or end with ".*" if that is what is desired. -# Trailing newlines are stripped from the command's actual output before -# matching against OUTPUT. -# If OUTPUT2 is specified and the output matches it, then it is also -# a pass (partial workaround for the fact that some versions of expr -# lack \|). -dotest () -{ - rm -f ${TESTDIR}/dotest.ex? 2>&1 - eval "$2" >${TESTDIR}/dotest.tmp 2>&1 - status=$? - if test "$status" != 0; then - cat ${TESTDIR}/dotest.tmp >>${LOGFILE} - echo "exit status was $status" >>${LOGFILE} - fail "$1" - fi - dotest_internal "$@" -} - -# Like dotest except only 2 args and result must exactly match stdin -dotest_lit () -{ - rm -f ${TESTDIR}/dotest.ex? 2>&1 - eval "$2" >${TESTDIR}/dotest.tmp 2>&1 - status=$? - if test "$status" != 0; then - cat ${TESTDIR}/dotest.tmp >>${LOGFILE} - echo "exit status was $status" >>${LOGFILE} - fail "$1" - fi - cat >${TESTDIR}/dotest.exp - if cmp ${TESTDIR}/dotest.exp ${TESTDIR}/dotest.tmp >/dev/null 2>&1; then - pass "$1" - verify_tmp_empty "$1" - else - echo "** expected: " >>${LOGFILE} - cat ${TESTDIR}/dotest.exp >>${LOGFILE} - echo "** got: " >>${LOGFILE} - cat ${TESTDIR}/dotest.tmp >>${LOGFILE} - fail "$1" - fi -} - -# Like dotest except exitstatus should be nonzero. -dotest_fail () -{ - rm -f ${TESTDIR}/dotest.ex? 2>&1 - eval "$2" >${TESTDIR}/dotest.tmp 2>&1 - status=$? - if test "$status" = 0; then - cat ${TESTDIR}/dotest.tmp >>${LOGFILE} - echo "exit status was $status" >>${LOGFILE} - fail "$1" - fi - dotest_internal "$@" -} - -# Like dotest except output is sorted. -dotest_sort () -{ - rm -f ${TESTDIR}/dotest.ex? 2>&1 - eval "$2" >${TESTDIR}/dotest.tmp1 2>&1 - status=$? - if test "$status" != 0; then - cat ${TESTDIR}/dotest.tmp1 >>${LOGFILE} - echo "exit status was $status" >>${LOGFILE} - fail "$1" - fi - ${TR} ' ' ' ' < ${TESTDIR}/dotest.tmp1 | sort > ${TESTDIR}/dotest.tmp - dotest_internal "$@" -} - -# A function for fetching the timestamp of a revison of a file -getrlogdate () { - ${testcvs} -n rlog -N ${1+"$@"} | - while read token value; do - case "$token" in - date:) - echo $value | sed "s,;.*,," - break; - ;; - esac - done -} - -# Avoid picking up any stray .cvsrc, etc., from the user running the tests -mkdir home -HOME=${TESTDIR}/home; export HOME - -# Make sure this variable is not defined to anything that would -# change the format of rcs dates. Otherwise people using e.g., -# RCSINIT=-zLT get lots of spurious failures. -RCSINIT=; export RCSINIT - -# Remaining arguments are the names of tests to run. -# -# The testsuite is broken up into (hopefully manageably-sized) -# independently runnable tests, so that one can quickly get a result -# from a cvs or testsuite change, and to facilitate understanding the -# tests. - -if test x"$*" = x; then - # Basic/miscellaneous functionality - tests="version basica basicb basicc basic1 deep basic2" - tests="${tests} parseroot parseroot2 files spacefiles commit-readonly" - tests="${tests} commit-add-missing" - tests="$tests add-restricted" - tests="${tests} status" - # Branching, tagging, removing, adding, multiple directories - tests="${tests} rdiff rdiff-short" - tests="${tests} rdiff2 diff diffnl death death2 death-rtag" - tests="${tests} rm-update-message rmadd rmadd2 rmadd3 resurrection" - tests="${tests} dirs dirs2 branches branches2 tagc tagf " - tests="${tests} tag-log tag-space" - tests="${tests} rcslib multibranch import importb importc import-CVS" - tests="$tests import-quirks" - tests="${tests} update-p import-after-initial branch-after-import" - tests="${tests} join join2 join3 join4 join5 join6 join7 join8 join9" - tests="${tests} join-readonly-conflict join-admin join-admin-2" - tests="${tests} join-rm" - tests="${tests} new newb conflicts conflicts2 conflicts3 conflicts4" - tests="${tests} clean" - # Checking out various places (modules, checkout -d, &c) - tests="${tests} modules modules2 modules3 modules4 modules5 modules6" - tests="${tests} modules7 mkmodules co-d" - tests="${tests} cvsadm emptydir abspath abspath2 toplevel toplevel2" - tests="${tests} rstar-toplevel trailingslashes checkout_repository" - # Log messages, error messages. - tests="${tests} mflag editor errmsg1 errmsg2 adderrmsg opterrmsg" - # Watches, binary files, history browsing, &c. - tests="${tests} devcom devcom2 devcom3 watch4 watch5 watch6" - tests="${tests} unedit-without-baserev" - tests="${tests} ignore ignore-on-branch binfiles binfiles2 binfiles3" - tests="${tests} mcopy binwrap binwrap2" - tests="${tests} binwrap3 mwrap info taginfo config" - 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 crerepos-extssh rcs rcs2 rcs3 rcs4 rcs5 rcs6" - tests="$tests lockfiles backuprecover" - tests="${tests} sshstdio" - # More history browsing, &c. - tests="${tests} history" - tests="${tests} big modes modes2 modes3 stamps" - # PreservePermissions stuff: permissions, symlinks et al. - # tests="${tests} perms symlinks symlinks2 hardlinks" - # More tag and branch tests, keywords. - tests="${tests} sticky keyword keywordlog keywordname keyword2" - tests="${tests} head tagdate multibranch2 tag8k" - # "cvs admin", reserved checkouts. - tests="${tests} admin reserved" - # Nuts and bolts of diffing/merging (diff library, &c) - tests="${tests} diffmerge1 diffmerge2" - # Release of multiple directories - tests="${tests} release" - tests="${tests} recase" - # Multiple root directories and low-level protocol tests. - tests="${tests} multiroot multiroot2 multiroot3 multiroot4" - tests="$tests rmroot reposmv pserver server server2 server3" - tests="$tests client client2" - tests="${tests} dottedroot fork commit-d" -else - tests="$*" -fi - -# Now check the -f argument for validity. -if test -n "$fromtest"; then - # Don't allow spaces - they are our delimiters in tests - count=0 - for sub in $fromtest; do - count=`expr $count + 1` - done - if test $count != 1; then - echo "No such test \`$fromtest'." >&2 - exit 2 - fi - # make sure it is in $tests - case " $tests " in - *" $fromtest "*) - ;; - *) - echo "No such test \`$fromtest'." >&2 - exit 2 - ;; - esac -fi - - - -# a simple function to compare directory contents -# -# Returns: 0 for same, 1 for different -# -directory_cmp () -{ - OLDPWD=`pwd` - DIR_1=$1 - DIR_2=$2 - - cd $DIR_1 - find . -print | fgrep -v /CVS | sort > $TESTDIR/dc$$d1 - - # go back where we were to avoid symlink hell... - cd $OLDPWD - cd $DIR_2 - find . -print | fgrep -v /CVS | sort > $TESTDIR/dc$$d2 - - if diff $TESTDIR/dc$$d1 $TESTDIR/dc$$d2 >/dev/null 2>&1 - then - : - else - return 1 - fi - cd $OLDPWD - while read a - do - if test -f $DIR_1/"$a" ; then - cmp -s $DIR_1/"$a" $DIR_2/"$a" - if test $? -ne 0 ; then - return 1 - fi - fi - done < $TESTDIR/dc$$d1 - rm -f $TESTDIR/dc$$* - return 0 -} - - - -# -# The following 4 functions are used by the diffmerge1 test case. They set up, -# respectively, the four versions of the files necessary: -# -# 1. Ancestor revisions. -# 2. "Your" changes. -# 3. "My" changes. -# 4. Expected merge result. -# - -# Create ancestor revisions for diffmerge1 -diffmerge_create_older_files() { - # This test case was supplied by Noah Friedman: - cat >testcase01 <<EOF -// Button.java - -package random.application; - -import random.util.*; - -public class Button -{ - /* Instantiates a Button with origin (0, 0) and zero width and height. - * You must call an initializer method to properly initialize the Button. - */ - public Button () - { - super (); - - _titleColor = Color.black; - _disabledTitleColor = Color.gray; - _titleFont = Font.defaultFont (); - } - - /* Convenience constructor for instantiating a Button with - * bounds x, y, width, and height. Equivalent to - * foo = new Button (); - * foo.init (x, y, width, height); - */ - public Button (int x, int y, int width, int height) - { - this (); - init (x, y, width, height); - } -} -EOF - - # This test case was supplied by Jacob Burckhardt: - cat >testcase02 <<EOF -a -a -a -a -a -EOF - - # This test case was supplied by Karl Tomlinson who also wrote the - # patch which lets CVS correctly handle this and several other cases: - cat >testcase03 <<EOF -x -s -a -b -s -y -EOF - - # This test case was supplied by Karl Tomlinson: - cat >testcase04 <<EOF -s -x -m -m -x -s -v -s -x -m -m -x -s -EOF - - # This test case was supplied by Karl Tomlinson: - cat >testcase05 <<EOF -s -x -m -m -x -x -x -x -x -x -x -x -x -x -s -s -s -s -s -s -s -s -s -s -v -EOF - - # This test case was supplied by Jacob Burckhardt: - cat >testcase06 <<EOF -g - - - - - - - - - - - -i -EOF - - # This test is supposed to verify that the horizon lines are the same - # for both 2-way diffs, but unfortunately, it does not fail with the - # old version of cvs. However, Karl Tomlinson still thought it would - # be good to test it anyway: - cat >testcase07 <<EOF -h -f - - - - - - - - - -g -r - - - -i - - - - - - - - - - -i -EOF - - # This test case was supplied by Jacob Burckhardt: - cat >testcase08 <<EOF -Both changes move this line to the end of the file. - -no -changes -here - -First change will delete this line. - -First change will also delete this line. - - no - changes - here - -Second change will change it here. - - no - changes - here -EOF - - # This test case was supplied by Jacob Burckhardt. Note that I do not - # think cvs has ever failed with this case, but I include it anyway, - # since I think it is a hard case. It is hard because Peter Miller's - # fmerge utility fails on it: - cat >testcase09 <<EOF -m -a -{ -} -b -{ -} -EOF - - # This test case was supplied by Martin Dorey and simplified by Jacob - # Burckhardt: - cat >testcase10 <<EOF - - petRpY ( MtatRk ); - fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG ); - - MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek ); - OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep ); - - Bloke_GttpfIRte_MtpeaL ( &acI ); -MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep ) -{ - fV ( Y < 16 ) - { - petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep + - Y * jfle_Uecopd_MfJe_fY_Mectopk, - jfle_Uecopd_MfJe_fY_Mectopk, - nRVVep ) ); - } - elke - { - petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep + - ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk, - jfle_Uecopd_MfJe_fY_Mectopk, - nRVVep ) ); - } - -} - - -/**************************************************************************** -* * -* Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY ) * -* * -****************************************************************************/ - -MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep ) -{ -MTGTXM MtatRk = Zy; - - MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep ); - - petRpY ( MtatRk ); - -} - HfkQipfte ( waYdle, /* waYdle */ - waYdleFok, /* ZVVket VpoL ktapt oV dfkQ */ - (coYkt RfYt8*) nRVVep, /* nRVVep */ - 0, /* MRrepVlRoRk KfxoYfkL */ - beYgtz /* nEtek to Apfte */ - ); - - petRpY ( Zy ); -} -EOF -} - -# Create "your" revisions for diffmerge1 -diffmerge_create_your_files() { - # remove the Button() method - cat >testcase01 <<\EOF -// Button.java - -package random.application; - -import random.util.*; - -public class Button -{ - /* Instantiates a Button with origin (0, 0) and zero width and height. - * You must call an initializer method to properly initialize the Button. - */ - public Button () - { - super (); - - _titleColor = Color.black; - _disabledTitleColor = Color.gray; - _titleFont = Font.defaultFont (); - } -} -EOF - - cat >testcase02 <<\EOF -y -a -a -a -a -EOF - - cat >testcase03 <<\EOF -x -s -a -b -s -b -s -y -EOF - - cat >testcase04 <<\EOF -s -m -s -v -s -m -s -EOF - - cat >testcase05 <<\EOF -v -s -m -s -s -s -s -s -s -s -s -s -s -v -EOF - - # Test case 6 and test case 7 both use the same input files, but they - # order the input files differently. In one case, a certain file is - # used as the older file, but in the other test case, that same file - # is used as the file which has changes. I could have put echo - # commands here, but since the echo lines would be the same as those - # in the previous function, I decided to save space and avoid repeating - # several lines of code. Instead, I merely swap the files: - mv testcase07 tmp - mv testcase06 testcase07 - mv tmp testcase06 - - # Make the date newer so that cvs thinks that the files are changed: - touch testcase06 testcase07 - - cat >testcase08 <<\EOF -no -changes -here - -First change has now added this in. - - no - changes - here - -Second change will change it here. - - no - changes - here - -Both changes move this line to the end of the file. -EOF - - cat >testcase09 <<\EOF - -m -a -{ -} -b -{ -} -c -{ -} -EOF - - cat >testcase10 <<\EOF - - fV ( BzQkV_URYYfYg ) (*jfle_Uecopdk)[0].jfle_Uecopd_KRLIep = ZpfgfYal_jUK; - - petRpY ( MtatRk ); - fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG ); - - fV ( jfle_Uecopd_KRLIep < 16 ) - { - MtatRk = Uead_Ktz_qjT_jfle_Uecopd ( jfle_Uecopd_KRLIep, (uofd*)nRVVep ); - } - elke - { - MtatRk = ZreY_GttpfIRte_MtpeaL ( qjT_jfle_Uecopdk, qjT_jfle_Uecopd_BoRYt, HGTG_TvFD, KXbb, KXbb, &acI ); - fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG ); - - MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek ); - OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep ); - - Bloke_GttpfIRte_MtpeaL ( &acI ); -MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep ) -{ -MTGTXM MtatRk = Zy; - - fV ( Y < 16 ) - { - petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep + - Y * jfle_Uecopd_MfJe_fY_Mectopk, - jfle_Uecopd_MfJe_fY_Mectopk, - nRVVep ) ); - } - elke - { - petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep + - ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk, - jfle_Uecopd_MfJe_fY_Mectopk, - nRVVep ) ); - } - - petRpY ( MtatRk ); - -} - - -/**************************************************************************** -* * -* Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY ) * -* * -****************************************************************************/ - -MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep ) -{ -MTGTXM MtatRk = Zy; - - MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep ); - - petRpY ( MtatRk ); - -} - HfkQipfte ( waYdle, /* waYdle */ - waYdleFok, /* ZVVket VpoL ktapt oV dfkQ */ - (coYkt RfYt8*) nRVVep, /* nRVVep */ - 0, /* MRrepVlRoRk KfxoYfkL */ - beYgtz /* nEtek to Apfte */ - ); - - petRpY ( Zy ); -} - -EOF -} - -# Create "my" revisions for diffmerge1 -diffmerge_create_my_files() { - # My working copy still has the Button() method, but I - # comment out some code at the top of the class. - cat >testcase01 <<\EOF -// Button.java - -package random.application; - -import random.util.*; - -public class Button -{ - /* Instantiates a Button with origin (0, 0) and zero width and height. - * You must call an initializer method to properly initialize the Button. - */ - public Button () - { - super (); - - // _titleColor = Color.black; - // _disabledTitleColor = Color.gray; - // _titleFont = Font.defaultFont (); - } - - /* Convenience constructor for instantiating a Button with - * bounds x, y, width, and height. Equivalent to - * foo = new Button (); - * foo.init (x, y, width, height); - */ - public Button (int x, int y, int width, int height) - { - this (); - init (x, y, width, height); - } -} -EOF - - cat >testcase02 <<\EOF -a -a -a -a -m -EOF - - cat >testcase03 <<\EOF -x -s -c -s -b -s -y -EOF - - cat >testcase04 <<\EOF -v -s -x -m -m -x -s -v -s -x -m -m -x -s -v -EOF - - # Note that in test case 5, there are no changes in the "mine" - # section, which explains why there is no command here which writes to - # file testcase05. - - # no changes for testcase06 - - # The two branches make the same changes: - cp ../yours/testcase07 . - - cat >testcase08 <<\EOF -no -changes -here - -First change will delete this line. - -First change will also delete this line. - - no - changes - here - -Second change has now changed it here. - - no - changes - here - -Both changes move this line to the end of the file. -EOF - - cat >testcase09 <<\EOF -m -a -{ -} -b -{ -} -c -{ -} -EOF - - cat >testcase10 <<\EOF - - petRpY ( MtatRk ); - fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG ); - - MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek ); - OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep ); - - Bloke_GttpfIRte_MtpeaL ( &acI ); -MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep ) -{ - fV ( Y < 16 ) - { - petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep + - Y * jfle_Uecopd_MfJe_fY_Mectopk, - jfle_Uecopd_MfJe_fY_Mectopk, - nRVVep ) ); - } - elke - { - petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep + - ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk, - jfle_Uecopd_MfJe_fY_Mectopk, - nRVVep ) ); - } - -} - - -/**************************************************************************** -* * -* Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY ) * -* * -****************************************************************************/ - -MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep ) -{ -MTGTXM MtatRk = Zy; - - MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep ); - - petRpY ( MtatRk ); - -} - HfkQipfte ( waYdle, /* waYdle */ - waYdleFok, /* ZVVket VpoL ktapt oV dfkQ */ - (coYkt RfYt8*) nRVVep, /* nRVVep */ - beYgtz /* nEtek to Apfte */ - ); - - petRpY ( Zy ); -} - -EOF -} - -# Create expected results of merge for diffmerge1 -diffmerge_create_expected_files() { - cat >testcase01 <<\EOF -// Button.java - -package random.application; - -import random.util.*; - -public class Button -{ - /* Instantiates a Button with origin (0, 0) and zero width and height. - * You must call an initializer method to properly initialize the Button. - */ - public Button () - { - super (); - - // _titleColor = Color.black; - // _disabledTitleColor = Color.gray; - // _titleFont = Font.defaultFont (); - } -} -EOF - - cat >testcase02 <<\EOF -y -a -a -a -m -EOF - - cat >testcase03 <<\EOF -x -s -c -s -b -s -b -s -y -EOF - - cat >testcase04 <<\EOF -v -s -m -s -v -s -m -s -v -EOF - - # Since there are no changes in the "mine" section, just take exactly - # the version in the "yours" section: - cp ../yours/testcase05 . - - cp ../yours/testcase06 . - - # Since the two branches make the same changes, the result should be - # the same as both branches. Here, I happen to pick yours to copy from, - # but I could have also picked mine, since the source of the copy is - # the same in either case. However, the mine has already been - # altered by the update command, so don't use it. Instead, use the - # yours section which has not had an update on it and so is unchanged: - cp ../yours/testcase07 . - - cat >testcase08 <<\EOF -no -changes -here - -First change has now added this in. - - no - changes - here - -Second change has now changed it here. - - no - changes - here - -Both changes move this line to the end of the file. -EOF - - cat >testcase09 <<\EOF - -m -a -{ -} -b -{ -} -c -{ -} -EOF - - cat >testcase10 <<\EOF - - fV ( BzQkV_URYYfYg ) (*jfle_Uecopdk)[0].jfle_Uecopd_KRLIep = ZpfgfYal_jUK; - - petRpY ( MtatRk ); - fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG ); - - fV ( jfle_Uecopd_KRLIep < 16 ) - { - MtatRk = Uead_Ktz_qjT_jfle_Uecopd ( jfle_Uecopd_KRLIep, (uofd*)nRVVep ); - } - elke - { - MtatRk = ZreY_GttpfIRte_MtpeaL ( qjT_jfle_Uecopdk, qjT_jfle_Uecopd_BoRYt, HGTG_TvFD, KXbb, KXbb, &acI ); - fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG ); - - MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek ); - OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep ); - - Bloke_GttpfIRte_MtpeaL ( &acI ); -MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep ) -{ -MTGTXM MtatRk = Zy; - - fV ( Y < 16 ) - { - petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep + - Y * jfle_Uecopd_MfJe_fY_Mectopk, - jfle_Uecopd_MfJe_fY_Mectopk, - nRVVep ) ); - } - elke - { - petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep + - ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk, - jfle_Uecopd_MfJe_fY_Mectopk, - nRVVep ) ); - } - - petRpY ( MtatRk ); - -} - - -/**************************************************************************** -* * -* Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY ) * -* * -****************************************************************************/ - -MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep ) -{ -MTGTXM MtatRk = Zy; - - MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep ); - - petRpY ( MtatRk ); - -} - HfkQipfte ( waYdle, /* waYdle */ - waYdleFok, /* ZVVket VpoL ktapt oV dfkQ */ - (coYkt RfYt8*) nRVVep, /* nRVVep */ - beYgtz /* nEtek to Apfte */ - ); - - petRpY ( Zy ); -} - -EOF -} - - - -# Echo a new CVSROOT based on $1, $remote, and $remotehost -newroot() { - if $remote; then - if test -n "$remotehost"; then - echo :ext:$remotehost$1 - else - echo :fork:$1 - fi - else - echo $1 - fi -} - - - -# Set up CVSROOT (the crerepos tests will test operating without CVSROOT set). -# -# Currently we test :fork: and :ext: (see crerepos test). There is a -# known difference between the two in modes-15 (see comments there). -# -# :ext: can be tested against a remote machine if: -# -# 1. $remotehost is set using the `-h' option to this script. -# 2. ${CVS_RSH=rsh} $remotehost works. -# 3. The path to $TESTDIR is the same on both machines (symlinks are okay) -# 4. The path to $testcvs is the same on both machines (symlinks are okay) -# or $CVS_SERVER is overridden in this script's environment to point to -# a working CVS exectuable on the remote machine. -# -# Testing :pserver: would be hard (inetd issues). (How about using tcpserver -# and some high port number? DRP) - -# Allow CVS_SERVER to be overridden. This facilitates constructs like -# testing a local case-insensitive client against a remote case -# sensitive server and visa versa. -: ${CVS_SERVER=$testcvs}; export CVS_SERVER - -# Use a name which will be different than CVSROOT on case insensitive -# filesystems (e.g., HFS+) -CVSROOTDIR=cvsrootdir -if $linkroot; then - mkdir ${TESTDIR}/realcvsroot - ln -s realcvsroot ${TESTDIR}/${CVSROOTDIR} -fi -CVSROOT_DIRNAME=${TESTDIR}/${CVSROOTDIR} -CVSROOT=`newroot $CVSROOT_DIRNAME`; export CVSROOT - - - -### -### Init the repository. -### -dotest init-1 "$testcvs -d$CVSROOT_DIRNAME init" - -# Copy the admin files for restore_adm. -cp -Rp $CVSROOT_DIRNAME/CVSROOT $TESTDIR/CVSROOT.save - - - -### -### The tests -### -if $remote; then - localonly init-2 - localonly init-3 -else - dotest init-2 "$testcvs init" - dotest_fail init-3 "$testcvs -d $CVSROOT/sdir init" \ -"$PROG \[init aborted\]: Cannot initialize repository under existing CVSROOT: \`$CVSROOT_DIRNAME'" -fi - - - -### The big loop -for what in $tests; do - if test -n "$fromtest" ; then - if test $fromtest = $what ; then - unset fromtest - else - continue - fi - fi - - if $verbose; then - echo "$what:" - fi - - case $what in - - version) - # We've had cases where the version command started dumping core, - # so we might as well test it - dotest version-1 "${testcvs} --version" \ -' -Concurrent Versions System (CVS) [0-9.]*.* - -Copyright (C) [0-9]* Free Software Foundation, Inc. - -Senior active maintainers include Larry Jones, Derek R. Price, -and Mark D. Baushke. Please see the AUTHORS and README files from the CVS -distribution kit for a complete list of contributors and copyrights. - -CVS may be copied only under the terms of the GNU General Public License, -a copy of which can be found with the CVS distribution kit. - -Specify the --help option for further information about CVS' - - if $remote; then - dotest version-2r "${testcvs} version" \ -'Client: Concurrent Versions System (CVS) [0-9p.]* (client/server) -Server: Concurrent Versions System (CVS) [0-9p.]* (client/server)' - else - dotest version-2 "${testcvs} version" \ -'Concurrent Versions System (CVS) [0-9.]*.*' - fi - ;; - - basica) - # Similar in spirit to some of the basic1, and basic2 - # tests, but hopefully a lot faster. Also tests operating on - # files two directories down *without* operating on the parent dirs. - - # Tests basica-0a and basica-0b provide the equivalent of the: - # mkdir ${CVSROOT_DIRNAME}/first-dir - # used by many of the tests. It is "more official" in the sense - # that is does everything through CVS; the reason most of the - # tests don't use it is mostly historical. - mkdir 1; cd 1 - dotest basica-0a "${testcvs} -q co -l ." '' - mkdir first-dir - dotest basica-0b "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd .. - rm -r 1 - - dotest basica-1 "${testcvs} -q co first-dir" '' - cd first-dir - - # Test a few operations, to ensure they gracefully do - # nothing in an empty directory. - dotest basica-1a0 "${testcvs} -q update" '' - dotest basica-1a1 "${testcvs} -q diff -c" '' - dotest basica-1a2 "${testcvs} -q status" '' - dotest basica-1a3 "${testcvs} -q update ." '' - dotest basica-1a4 "${testcvs} -q update ./" '' - - mkdir sdir - # Remote CVS gives the "cannot open CVS/Entries" error, which is - # clearly a bug, but not a simple one to fix. - dotest basica-1a10 "${testcvs} -n add sdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/sdir added to the repository" \ -"${PROG} add: cannot open CVS/Entries for reading: No such file or directory -Directory ${CVSROOT_DIRNAME}/first-dir/sdir added to the repository" - dotest_fail basica-1a11 \ - "test -d ${CVSROOT_DIRNAME}/first-dir/sdir" '' - dotest basica-2 "${testcvs} add sdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/sdir added to the repository" - cd sdir - mkdir ssdir - dotest basica-3 "${testcvs} add ssdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir added to the repository" - cd ssdir - echo ssfile >ssfile - - # Trying to commit it without a "cvs add" should be an error. - # The "use `cvs add' to create an entry" message is the one - # that I consider to be more correct, but local cvs prints the - # "nothing known" message and noone has gotten around to fixing it. - dotest_fail basica-notadded "${testcvs} -q ci ssfile" \ -"${PROG} [a-z]*: use .${PROG} add. to create an entry for ssfile -${PROG}"' \[[a-z]* aborted\]: correct above errors first!' \ -"${PROG}"' [a-z]*: nothing known about `ssfile'\'' -'"${PROG}"' \[[a-z]* aborted\]: correct above errors first!' - - dotest basica-4 "${testcvs} add ssfile" \ -"${PROG}"' add: scheduling file `ssfile'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest_fail basica-4a "${testcvs} tag tag0 ssfile" \ -"${PROG} tag: nothing known about ssfile -${PROG} "'\[tag aborted\]: correct the above errors first!' - cd ../.. - dotest basica-5 "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -done -Checking in sdir/ssdir/ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -initial revision: 1\.1 -done" - dotest_fail basica-5a \ - "${testcvs} -q tag BASE sdir/ssdir/ssfile" \ -"${PROG} tag: Attempt to add reserved tag name BASE -${PROG} \[tag aborted\]: failed to set tag BASE to revision 1\.1 in ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v" - dotest basica-5b "${testcvs} -q tag NOT_RESERVED" \ -'T sdir/ssdir/ssfile' - - dotest basica-6 "${testcvs} -q update" '' - echo "ssfile line 2" >>sdir/ssdir/ssfile - dotest_fail basica-6.2 "${testcvs} -q diff -c" \ -"Index: sdir/ssdir/ssfile -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -retrieving revision 1\.1 -diff -c -r1\.1 ssfile -\*\*\* sdir/ssdir/ssfile ${RFCDATE} 1\.1 ---- sdir/ssdir/ssfile ${RFCDATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* ---- 1,2 ---- - ssfile -${PLUS} ssfile line 2" - dotest_fail basica-6.3 "${testcvs} -q diff -c -rBASE" \ -"Index: sdir/ssdir/ssfile -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -retrieving revision 1\.1 -diff -c -r1\.1 ssfile -\*\*\* sdir/ssdir/ssfile ${RFCDATE} 1\.1 ---- sdir/ssdir/ssfile ${RFCDATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* ---- 1,2 ---- - ssfile -${PLUS} ssfile line 2" - dotest_fail basica-6.4 "${testcvs} -q diff -c -rBASE -C3isacrowd" \ -"Index: sdir/ssdir/ssfile -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -retrieving revision 1\.1 -diff -c -C 3isacrowd -r1\.1 ssfile -${PROG} diff: invalid context length argument" - dotest basica-7 "${testcvs} -q ci -m modify-it" \ -"Checking in sdir/ssdir/ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 1\.2; previous revision: 1\.1 -done" - dotest_fail basica-nonexist "${testcvs} -q ci nonexist" \ -"${PROG}"' [a-z]*: nothing known about `nonexist'\'' -'"${PROG}"' \[[a-z]* aborted\]: correct above errors first!' - dotest basica-8 "${testcvs} -q update ." '' - - # Test the -f option to ci - cd sdir/ssdir - dotest basica-8a0 "${testcvs} -q ci -m not-modified ssfile" '' - dotest basica-8a "${testcvs} -q ci -f -m force-it" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 1\.3; previous revision: 1\.2 -done" - dotest basica-8a1 "${testcvs} -q ci -m bump-it -r 2.0" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 2\.0; previous revision: 1\.3 -done" - dotest basica-8a1a "${testcvs} -q ci -m bump-it -r 2.9" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 2\.9; previous revision: 2\.0 -done" - # Test string-based revion number increment rollover - dotest basica-8a1b "${testcvs} -q ci -m bump-it -f -r 2" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 2\.10; previous revision: 2\.9 -done" - dotest basica-8a1c "${testcvs} -q ci -m bump-it -r 2.99" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 2\.99; previous revision: 2\.10 -done" - # Test string-based revion number increment rollover - dotest basica-8a1d "${testcvs} -q ci -m bump-it -f -r 2" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 2\.100; previous revision: 2\.99 -done" - dotest basica-8a1e "${testcvs} -q ci -m bump-it -r 2.1099" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 2\.1099; previous revision: 2\.100 -done" - # Test string-based revion number increment rollover - dotest basica-8a1f "${testcvs} -q ci -m bump-it -f -r 2" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 2\.1100; previous revision: 2\.1099 -done" - # -f should not be necessary, but it should be harmless. - # Also test the "-r 3" (rather than "-r 3.0") usage. - dotest basica-8a2 "${testcvs} -q ci -m bump-it -f -r 3" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 3\.1; previous revision: 2\.1100 -done" - - # Test using -r to create a branch - dotest_fail basica-8a3 "${testcvs} -q ci -m bogus -r 3.0.0" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -${PROG} commit: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v: can't find branch point 3\.0 -${PROG} commit: could not check in ssfile" - dotest basica-8a4 "${testcvs} -q ci -m valid -r 3.1.2" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 3\.1\.2\.1; previous revision: 3\.1 -done" - - # Verify that this file remains unchanged since up -A should not - # change the contents here. - cp ssfile $TESTDIR/ssfile.sav - # now get rid of the sticky tag and go back to the trunk - dotest basica-8a5 "$testcvs -q up -A ./" '[UP] ssfile' - dotest basica-8a6 "cmp ssfile $TESTDIR/ssfile.sav" - rm $TESTDIR/ssfile.sav - - cd ../.. - dotest basica-8b "${testcvs} -q diff -r1.2 -r1.3" - dotest basica-8b1 "${testcvs} -q diff -r1.2 -r1.3 -C 3isacrowd" - - # 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 \ - "${testcvs} -q -d ${TESTDIR}/nonexist update" \ -"${PROG}: cannot access cvs root ${TESTDIR}/nonexist: .*" - dotest_fail basica-9 \ - "${testcvs} -q -d ${TESTDIR}/nonexist update" \ -"${PROG} \[[a-z]* aborted\]: ${TESTDIR}/nonexist/CVSROOT: .*" - - dotest basica-10 "${testcvs} annotate" \ -' -Annotations for sdir/ssdir/ssfile -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1 .'"$username8"' *[0-9a-zA-Z-]*.: ssfile -1\.2 .'"$username8"' *[0-9a-zA-Z-]*.: ssfile line 2' - - # Test resurrecting with strange revision numbers - cd sdir/ssdir - dotest basica-r1 "${testcvs} rm -f ssfile" \ -"${PROG} remove: scheduling .ssfile. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest basica-r2 "${testcvs} -q ci -m remove" \ -"Removing ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: delete; previous revision: 3\.1 -done" - dotest basica-r3 "${testcvs} -q up -p -r 3.1 ./ssfile >ssfile" "" - dotest basica-r4 "${testcvs} add ssfile" \ -"${PROG} add: Re-adding file .ssfile. (in place of dead revision 3\.2)\. -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest basica-r5 "${testcvs} -q ci -m resurrect" \ -"Checking in ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v <-- ssfile -new revision: 3\.3; previous revision: 3\.2 -done" - cd ../.. - - # As long as we have a file with a few revisions, test - # a few "cvs admin -o" invocations. - cd sdir/ssdir - dotest_fail basica-o1 "${testcvs} admin -o 1.2::1.2" \ -"${PROG} [a-z]*: while processing more than one file: -${PROG} \[[a-z]* aborted\]: attempt to specify a numeric revision" - dotest basica-o2 "${testcvs} admin -o 1.2::1.2 ssfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -done" - dotest basica-o2a "${testcvs} admin -o 1.1::NOT_RESERVED ssfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -done" - dotest_fail basica-o2b "${testcvs} admin -o 1.1::NOT_EXIST ssfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v: Revision NOT_EXIST doesn't exist. -${PROG} admin: RCS file for .ssfile. not modified\." - dotest basica-o3 "${testcvs} admin -o 1.2::1.3 ssfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -done" - dotest basica-o4 "${testcvs} admin -o 3.1:: ssfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -deleting revision 3\.3 -deleting revision 3\.2 -done" - dotest basica-o5 "${testcvs} admin -o ::1.1 ssfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -done" - dotest basica-o5a "${testcvs} -n admin -o 1.2::3.1 ssfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -deleting revision 2\.1100 -deleting revision 2\.1099 -deleting revision 2\.100 -deleting revision 2\.99 -deleting revision 2\.10 -deleting revision 2\.9 -deleting revision 2\.0 -deleting revision 1\.3 -done" - dotest basica-o6 "${testcvs} admin -o 1.2::3.1 ssfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -deleting revision 2\.1100 -deleting revision 2\.1099 -deleting revision 2\.100 -deleting revision 2\.99 -deleting revision 2\.10 -deleting revision 2\.9 -deleting revision 2\.0 -deleting revision 1\.3 -done" - dotest basica-o6a "${testcvs} admin -o 3.1.2: ssfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -deleting revision 3\.1\.2\.1 -done" - dotest basica-o7 "${testcvs} log -N ssfile" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v -Working file: ssfile -head: 3\.1 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 3; selected revisions: 3 -description: ----------------------------- -revision 3\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}0 -0 -bump-it ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -modify-it ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -add-it -=============================================================================" - dotest basica-o8 "${testcvs} -q update -p -r 1.1 ./ssfile" "ssfile" - cd ../.. - - cd .. - - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -r first-dir - ;; - - basicb) - # More basic tests, including non-branch tags and co -d. - mkdir 1; cd 1 - dotest basicb-0a "${testcvs} -q co -l ." '' - touch topfile - dotest basicb-0b "${testcvs} add topfile" \ -"${PROG} add: scheduling file .topfile. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest basicb-0c "${testcvs} -q ci -m add-it topfile" \ -"RCS file: ${CVSROOT_DIRNAME}/topfile,v -done -Checking in topfile; -${CVSROOT_DIRNAME}/topfile,v <-- topfile -initial revision: 1\.1 -done" - cd .. - rm -r 1 - mkdir 2; cd 2 - dotest basicb-0d "${testcvs} -q co -l ." "U topfile" - # Now test the ability to run checkout on an existing working - # directory without having it lose its mind. I don't know - # whether this is tested elsewhere in sanity.sh. A more elaborate - # test might also have modified files, make sure it works if - # the modules file was modified to add new directories to the - # module, and such. - dotest basicb-0d0 "${testcvs} -q co -l ." "" - mkdir first-dir - dotest basicb-0e "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd .. - rm -r 2 - - dotest basicb-1 "${testcvs} -q co first-dir" '' - - # The top-level CVS directory is not created by default. - # I'm leaving basicb-1a and basicb-1b untouched, mostly, in - # case we decide that the default should be reversed... - - dotest_fail basicb-1a "test -d CVS" '' - - dotest basicb-1c "cat first-dir/CVS/Repository" "first-dir" - - cd first-dir - # Note that the name Emptydir is chosen to test that CVS just - # treats it like any other directory name. It should be - # special only when it is directly in $CVSROOT/CVSROOT. - mkdir Emptydir sdir2 - dotest basicb-2 "${testcvs} add Emptydir sdir2" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/Emptydir added to the repository -Directory ${CVSROOT_DIRNAME}/first-dir/sdir2 added to the repository" - cd Emptydir - echo sfile1 starts >sfile1 - dotest basicb-2a10 "${testcvs} -n add sfile1" \ -"${PROG} add: scheduling file .sfile1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest basicb-2a11 "${testcvs} status sfile1" \ -"${PROG} status: use .${PROG} add. to create an entry for sfile1 -=================================================================== -File: sfile1 Status: Unknown - - Working revision: No entry for sfile1 - Repository revision: No revision control file" - dotest basicb-3 "${testcvs} add sfile1" \ -"${PROG} add: scheduling file .sfile1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest basicb-3a1 "${testcvs} status sfile1" \ -"=================================================================== -File: sfile1 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - - cd ../sdir2 - echo sfile2 starts >sfile2 - dotest basicb-4 "${testcvs} add sfile2" \ -"${PROG} add: scheduling file .sfile2. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest basicb-4a "${testcvs} -q ci CVS" \ -"${PROG} [a-z]*: warning: directory CVS specified in argument -${PROG} [a-z]*: but CVS uses CVS for its own purposes; skipping CVS directory" - cd .. - dotest basicb-5 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Emptydir/sfile1,v -done -Checking in Emptydir/sfile1; -${CVSROOT_DIRNAME}/first-dir/Emptydir/sfile1,v <-- sfile1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir2/sfile2,v -done -Checking in sdir2/sfile2; -${CVSROOT_DIRNAME}/first-dir/sdir2/sfile2,v <-- sfile2 -initial revision: 1\.1 -done" - echo sfile1 develops >Emptydir/sfile1 - dotest basicb-6 "${testcvs} -q ci -m modify" \ -"Checking in Emptydir/sfile1; -${CVSROOT_DIRNAME}/first-dir/Emptydir/sfile1,v <-- sfile1 -new revision: 1\.2; previous revision: 1\.1 -done" - dotest basicb-7 "${testcvs} -q tag release-1" 'T Emptydir/sfile1 -T sdir2/sfile2' - echo not in time for release-1 >sdir2/sfile2 - dotest basicb-8 "${testcvs} -q ci -m modify-2" \ -"Checking in sdir2/sfile2; -${CVSROOT_DIRNAME}/first-dir/sdir2/sfile2,v <-- sfile2 -new revision: 1\.2; previous revision: 1\.1 -done" - # See if CVS can correctly notice when an invalid numeric - # revision is specified. - # Commented out until we get around to fixing CVS -: dotest basicb-8a0 "${testcvs} diff -r 1.5 -r 1.7 sfile2" 'error msg' - cd .. - - # Test that we recurse into the correct directory when checking - # for existing files, even if co -d is in use. - touch first-dir/extra - dotest basicb-cod-1 "${testcvs} -q co -d first-dir1 first-dir" \ -'U first-dir1/Emptydir/sfile1 -U first-dir1/sdir2/sfile2' - rm -r first-dir1 - - rm -r first-dir - - # FIXME? basicb-9 used to check things out like this: - # U newdir/Emptydir/sfile1 - # U newdir/sdir2/sfile2 - # but that's difficult to do. The whole "shorten" thing - # is pretty bogus, because it will break on things - # like "cvs co foo/bar baz/quux". Unless there's some - # pretty detailed expansion and analysis of the command-line - # arguments, we shouldn't do "shorten" stuff at all. - - dotest basicb-9 \ -"${testcvs} -q co -d newdir -r release-1 first-dir/Emptydir first-dir/sdir2" \ -'U newdir/first-dir/Emptydir/sfile1 -U newdir/first-dir/sdir2/sfile2' - - # basicb-9a and basicb-9b: see note about basicb-1a - - dotest_fail basicb-9a "test -d CVS" '' - - dotest basicb-9c "cat newdir/CVS/Repository" "\." - dotest basicb-9d "cat newdir/first-dir/CVS/Repository" \ -"${CVSROOT_DIRNAME}/first-dir" \ -"first-dir" - dotest basicb-9e "cat newdir/first-dir/Emptydir/CVS/Repository" \ -"${CVSROOT_DIRNAME}/first-dir/Emptydir" \ -"first-dir/Emptydir" - dotest basicb-9f "cat newdir/first-dir/sdir2/CVS/Repository" \ -"${CVSROOT_DIRNAME}/first-dir/sdir2" \ -"first-dir/sdir2" - - dotest basicb-10 "cat newdir/first-dir/Emptydir/sfile1 newdir/first-dir/sdir2/sfile2" \ -"sfile1 develops -sfile2 starts" - - rm -r newdir - - # Hmm, this might be a case for CVSNULLREPOS, but CVS doesn't - # seem to deal with it... - if false; then - dotest basicb-11 "${testcvs} -q co -d sub1/sub2 first-dir" \ -"U sub1/sub2/Emptydir/sfile1 -U sub1/sub2/sdir2/sfile2" - cd sub1 - dotest basicb-12 "${testcvs} -q update ./." '' - touch xx - dotest basicb-13 "${testcvs} add xx" fixme - cd .. - rm -r sub1 - # to test: sub1/sub2/sub3 - fi # end of tests commented out. - - # Create a second directory. - mkdir 1 - cd 1 - dotest basicb-14 "${testcvs} -q co -l ." 'U topfile' - mkdir second-dir - dotest basicb-15 "${testcvs} add second-dir" \ -"Directory ${CVSROOT_DIRNAME}/second-dir added to the repository" - cd second-dir - touch aa - dotest basicb-16 "${testcvs} add aa" \ -"${PROG} add: scheduling file .aa. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest basicb-17 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/second-dir/aa,v -done -Checking in aa; -${CVSROOT_DIRNAME}/second-dir/aa,v <-- aa -initial revision: 1\.1 -done" - cd .. - - # Try to remove all revisions in a file. - dotest_fail basicb-o1 "${testcvs} admin -o1.1 topfile" \ -"RCS file: ${CVSROOT_DIRNAME}/topfile,v -deleting revision 1\.1 -${PROG} \[admin aborted\]: attempt to delete all revisions" - dotest basicb-o2 "${testcvs} -q update -d first-dir" \ -"U first-dir/Emptydir/sfile1 -U first-dir/sdir2/sfile2" - dotest_fail basicb-o3 \ -"${testcvs} admin -o1.1:1.2 first-dir/sdir2/sfile2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir2/sfile2,v -deleting revision 1\.2 -deleting revision 1\.1 -${PROG} \[admin aborted\]: attempt to delete all revisions" - cd .. - rm -r 1 - - mkdir 1; cd 1 - # Note that -H is an illegal option. - # I suspect that the choice between "illegal" and "invalid" - # depends on the user's environment variables, the phase - # of the moon (weirdness with optind), and who knows what else. - # I've been seeing "illegal"... - dotest_fail basicb-21 "${testcvs} -q admin -H" \ -"admin: illegal option -- H -${PROG} \[admin aborted\]: specify ${PROG} -H admin for usage information" \ -"admin: invalid option -- H -${PROG} \[admin aborted\]: specify ${PROG} -H admin for usage information" - cd .. - rmdir 1 - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -rf ${CVSROOT_DIRNAME}/second-dir - rm -f ${CVSROOT_DIRNAME}/topfile,v - ;; - - basicc) - # More tests of basic/miscellaneous functionality. - mkdir 1; cd 1 - dotest_fail basicc-1 "${testcvs} diff" \ -"${PROG} [a-z]*: in directory \.: -${PROG} \[[a-z]* aborted\]: there is no version here; run .${PROG} checkout. first" - dotest basicc-2 "${testcvs} -q co -l ." '' - mkdir first-dir second-dir - dotest basicc-3 "${testcvs} add first-dir second-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository -Directory ${CVSROOT_DIRNAME}/second-dir added to the repository" - # Old versions of CVS often didn't create this top-level CVS - # directory in the first place. I think that maybe the only - # way to get it to work currently is to let CVS create it, - # and then blow it away (don't complain if it does not - # exist). But that is perfectly legal; people who are used - # to the old behavior especially may be interested. - # FIXME: this test is intended for the TopLevelAdmin=yes case; - # should adjust/move it accordingly. - rm -rf CVS - dotest basicc-4 "echo *" "first-dir second-dir" - dotest basicc-5 "${testcvs} update" \ -"${PROG} update: Updating first-dir -${PROG} update: Updating second-dir" \ -"${PROG} update: Updating \. -${PROG} update: Updating first-dir -${PROG} update: Updating second-dir" - - cd first-dir - dotest basicc-6 "${testcvs} release -d" "" - dotest basicc-7 "test -d ../first-dir" "" - # The Linux 2.2 kernel lets you delete ".". That's OK either way, - # the point is that CVS must not mess with anything *outside* "." - # the way that CVS 1.10 and older tried to. - dotest basicc-8 "${testcvs} -Q release -d ." \ -"" "${PROG} release: deletion of directory \. failed: .*" - dotest basicc-9 "test -d ../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 - # Apparently `cd ..' doesn't work with Linux 2.2 & Bash 2.05b. - cd $TESTDIR/1 - mkdir ./first-dir - cd ./first-dir - fi - dotest basicc-11 "${testcvs} -Q release -d ./." \ -"" "${PROG} release: deletion of directory \./\. failed: .*" - dotest basicc-11a "test -d ../second-dir" "" - - cd ../.. - - mkdir 2; cd 2 - dotest basicc-12 "${testcvs} -Q co ." "" - # actual entries can be in either Entries or Entries.log, do - # an update to get them consolidated into Entries - dotest basicc-12a "${testcvs} -Q up" "" - dotest basicc-12b "cat CVS/Entries" \ -"D/CVSROOT//// -D/first-dir//// -D/second-dir////" - dotest basicc-13 "echo *" "CVS CVSROOT first-dir second-dir" - dotest basicc-14 "${testcvs} -Q release first-dir second-dir" "" - # a normal release shouldn't affect the Entries file - dotest basicc-14b "cat CVS/Entries" \ -"D/CVSROOT//// -D/first-dir//// -D/second-dir////" - # FIXCVS: but release -d probably should - dotest basicc-15 "${testcvs} -Q release -d first-dir second-dir" "" - dotest basicc-16 "echo *" "CVS CVSROOT" - dotest basicc-17 "cat CVS/Entries" \ -"D/CVSROOT//// -D/first-dir//// -D/second-dir////" - # FIXCVS: if not, update should notice the missing directories - # and update Entries accordingly - dotest basicc-18 "${testcvs} -Q up" "" - dotest basicc-19 "cat CVS/Entries" \ -"D/CVSROOT//// -D/first-dir//// -D/second-dir////" - - cd .. - rm -r 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - basic1) - # first dive - add a files, first singly, then in a group. - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir basic1; cd basic1 - # check out an empty directory - dotest basic1-1 "${testcvs} -q co first-dir" '' - - cd first-dir - echo file2 >file2 - echo file3 >file3 - echo file4 >file4 - echo file5 >file5 - - dotest basic1-14-add-add "${testcvs} add file2 file3 file4 file5" \ -"${PROG} add: scheduling file \`file2' for addition -${PROG} add: scheduling file \`file3' for addition -${PROG} add: scheduling file \`file4' for addition -${PROG} add: scheduling file \`file5' for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest basic1-15-add-add \ -"${testcvs} -q update file2 file3 file4 file5" \ -"A file2 -A file3 -A file4 -A file5" - dotest basic1-16-add-add "${testcvs} -q update" \ -"A file2 -A file3 -A file4 -A file5" - dotest basic1-17-add-add "${testcvs} -q status" \ -"=================================================================== -File: file2 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file3 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file4 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file5 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest basic1-18-add-add "${testcvs} -q log" \ -"${PROG} log: file2 has been added, but not committed -${PROG} log: file3 has been added, but not committed -${PROG} log: file4 has been added, but not committed -${PROG} log: file5 has been added, but not committed" - cd .. - dotest basic1-21-add-add "${testcvs} -q update" \ -"A first-dir/file2 -A first-dir/file3 -A first-dir/file4 -A first-dir/file5" - # FIXCVS? Shouldn't this read first-dir/file2 instead of file2? - dotest basic1-22-add-add "${testcvs} log first-dir" \ -"${PROG} log: Logging first-dir -${PROG} log: file2 has been added, but not committed -${PROG} log: file3 has been added, but not committed -${PROG} log: file4 has been added, but not committed -${PROG} log: file5 has been added, but not committed" - dotest basic1-23-add-add "${testcvs} status first-dir" \ -"${PROG} status: Examining first-dir -=================================================================== -File: file2 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file3 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file4 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file5 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest basic1-24-add-add "${testcvs} update first-dir" \ -"${PROG} update: Updating first-dir -A first-dir/file2 -A first-dir/file3 -A first-dir/file4 -A first-dir/file5" - dotest basic1-27-add-add "${testcvs} co first-dir" \ -"${PROG} checkout: Updating first-dir -A first-dir/file2 -A first-dir/file3 -A first-dir/file4 -A first-dir/file5" - cd first-dir - dotest basic1-14-add-ci \ -"${testcvs} commit -m test file2 file3 file4 file5" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file3,v -done -Checking in file3; -${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file5,v -done -Checking in file5; -${CVSROOT_DIRNAME}/first-dir/file5,v <-- file5 -initial revision: 1\.1 -done" - dotest basic1-15-add-ci \ -"${testcvs} -q update file2 file3 file4 file5" '' - dotest basic1-16-add-ci "${testcvs} -q update" '' - dotest basic1-17-add-ci "${testcvs} -q status" \ -"=================================================================== -File: file2 Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file2,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file3 Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file3,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file4 Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file4,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file5 Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file5,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - # The "log" tests and friends probably already test the output - # from log quite adequately. - # Note: using dotest fails here. It seems to be related - # to the output being sufficiently large (Red Hat 4.1). - # dotest basic1-18-add-ci "${testcvs} log" "${DOTSTAR}" - if ${testcvs} -q log >>${LOGFILE}; then - pass basic1-18-add-ci - else - pass basic1-18-add-ci - fi - cd .. - dotest basic1-21-add-ci "${testcvs} -q update" '' - # See test basic1-18-add-ci for explanation of non-use of dotest. - if ${testcvs} -q log first-dir >>${LOGFILE}; then - pass basic1-22-add-ci - else - pass basic1-22-add-ci - fi - # At least for the moment I am going to consider 17-add-ci - # an adequate test of the output here. - # See test basic1-18-add-ci for explanation of non-use of dotest. - if ${testcvs} -q status first-dir >>${LOGFILE}; then - pass basic1-23-add-ci - else - pass basic1-23-add-ci - fi - dotest basic1-24-add-ci "${testcvs} -q update first-dir" '' - dotest basic1-27-add-ci "${testcvs} -q co first-dir" '' - - cd first-dir - rm file2 file3 file4 file5 - dotest basic1-14-rm-rm "${testcvs} rm file2 file3 file4 file5" \ -"${PROG} remove: scheduling .file2. for removal -${PROG} remove: scheduling .file3. for removal -${PROG} remove: scheduling .file4. for removal -${PROG} remove: scheduling .file5. for removal -${PROG} remove: use .${PROG} commit. to remove these files permanently" - # 15-rm-rm was commented out. Why? - dotest basic1-15-rm-rm \ -"${testcvs} -q update file2 file3 file4 file5" \ -"R file2 -R file3 -R file4 -R file5" - dotest basic1-16-rm-rm "${testcvs} -q update" \ -"R file2 -R file3 -R file4 -R file5" - dotest basic1-17-rm-rm "${testcvs} -q status" \ -"=================================================================== -File: no file file2 Status: Locally Removed - - Working revision: -1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file2,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: no file file3 Status: Locally Removed - - Working revision: -1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file3,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: no file file4 Status: Locally Removed - - Working revision: -1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file4,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: no file file5 Status: Locally Removed - - Working revision: -1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file5,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - # Would be nice to test that real logs appear (with dead state - # and all), either here or someplace like log2 tests. - if ${testcvs} -q log >>${LOGFILE}; then - pass basic1-18-rm-rm - else - fail basic1-18-rm-rm - fi - cd .. - dotest basic1-21-rm-rm "${testcvs} -q update" \ -"R first-dir/file2 -R first-dir/file3 -R first-dir/file4 -R first-dir/file5" - if ${testcvs} -q log first-dir >>${LOGFILE}; then - pass basic1-22-rm-rm - else - fail basic1-22-rm-rm - fi - if ${testcvs} -q status first-dir >>${LOGFILE}; then - pass basic1-23-rm-rm - else - fail basic1-23-rm-rm - fi - dotest basic1-24-rm-rm "${testcvs} -q update first-dir" \ -"R first-dir/file2 -R first-dir/file3 -R first-dir/file4 -R first-dir/file5" - dotest basic1-27-rm-rm "${testcvs} -q co first-dir" \ -"R first-dir/file2 -R first-dir/file3 -R first-dir/file4 -R first-dir/file5" - cd first-dir - dotest basic1-14-rm-ci "${testcvs} -q commit -m test" \ -"Removing file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: delete; previous revision: 1\.1 -done -Removing file3; -${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3 -new revision: delete; previous revision: 1\.1 -done -Removing file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: delete; previous revision: 1\.1 -done -Removing file5; -${CVSROOT_DIRNAME}/first-dir/file5,v <-- file5 -new revision: delete; previous revision: 1\.1 -done" - dotest basic1-15-rm-ci \ -"${testcvs} -q update file2 file3 file4 file5" '' - dotest basic1-16-rm-ci "${testcvs} -q update" '' - dotest basic1-17-rm-ci "${testcvs} -q status" '' - # Would be nice to test that real logs appear (with dead state - # and all), either here or someplace like log2 tests. - if ${testcvs} -q log >>${LOGFILE}; then - pass basic1-18-rm-ci - else - fail basic1-18-rm-ci - fi - cd .. - dotest basic1-21-rm-ci "${testcvs} -q update" '' - if ${testcvs} -q log first-dir >>${LOGFILE}; then - pass basic1-22-rm-ci - else - fail basic1-22-rm-ci - fi - if ${testcvs} -q status first-dir >>${LOGFILE}; then - pass basic1-23-rm-ci - else - fail basic1-23-rm-ci - fi - dotest basic1-24-rm-ci "${testcvs} -q update first-dir" '' - dotest basic1-27-rm-ci "${testcvs} -q co first-dir" '' - cd first-dir - # All the files are removed, so nothing gets tagged. - dotest basic1-28 "${testcvs} -q tag first-dive" '' - cd .. - cd .. - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -r basic1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - deep) - # Test the ability to operate on directories nested rather deeply. - mkdir ${CVSROOT_DIRNAME}/first-dir - dotest deep-1 "${testcvs} -q co first-dir" '' - cd first-dir - for i in dir1 dir2 dir3 dir4 dir5 dir6 dir7 dir8; do - mkdir $i - dotest deep-2-$i "${testcvs} add $i" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir1[/dir0-9]* added to the repository" - cd $i - echo file1 >file1 - dotest deep-3-$i "${testcvs} add file1" \ -"${PROG}"' add: scheduling file `file1'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - done - cd ../../../../../../../../.. - dotest_lit deep-4 "${testcvs} -q ci -m add-them first-dir" <<HERE -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/file1,v -done -Checking in first-dir/dir1/file1; -${CVSROOT_DIRNAME}/first-dir/dir1/file1,v <-- file1 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file1,v -done -Checking in first-dir/dir1/dir2/file1; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file1,v <-- file1 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/file1,v -done -Checking in first-dir/dir1/dir2/dir3/file1; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/file1,v <-- file1 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/file1,v -done -Checking in first-dir/dir1/dir2/dir3/dir4/file1; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/file1,v <-- file1 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/file1,v -done -Checking in first-dir/dir1/dir2/dir3/dir4/dir5/file1; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/file1,v <-- file1 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/file1,v -done -Checking in first-dir/dir1/dir2/dir3/dir4/dir5/dir6/file1; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/file1,v <-- file1 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/file1,v -done -Checking in first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/file1; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/file1,v <-- file1 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/file1,v -done -Checking in first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/file1; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/file1,v <-- file1 -initial revision: 1.1 -done -HERE - - cd first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8 - rm file1 - dotest deep-4a0 "${testcvs} rm file1" \ -"${PROG} remove: scheduling .file1. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest deep-4a1 "${testcvs} -q ci -m rm-it" "Removing file1; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done" - cd ../../.. - dotest deep-4a2 "${testcvs} -q update -P dir6/dir7" '' - # Should be using "test -e" if that is portable enough. - dotest_fail deep-4a3 "test -d dir6/dir7/dir8" '' - - # Test that if we remove the working directory, CVS does not - # recreate it. (I realize that this behavior is what the - # users expect, but in the longer run we might want to - # re-think it. The corresponding behavior for a file is that - # CVS *will* recreate it, and we might want to make it so - # that "cvs release -d" is the way to delete the directory - # and have it stay gone -kingdon, Oct1996). - rm -r dir6 - dotest deep-4b0a "${testcvs} -q diff" '' - dotest deep-4b0b "${testcvs} -q ci" '' - dotest deep-4b1 "${testcvs} -q update" '' - dotest deep-4b2 "${testcvs} -q update -d -P" \ -'U dir6/file1 -U dir6/dir7/file1' - - # Test what happens if one uses -P when there are files removed - # but not committed. - cd dir6/dir7 - dotest deep-rm1 "${testcvs} rm -f file1" \ -"${PROG} remove: scheduling .file1. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - cd .. - dotest deep-rm2 "${testcvs} -q update -d -P" 'R dir7/file1' - dotest deep-rm3 "test -d dir7" '' - dotest deep-rm4 "${testcvs} -q ci -m rm-it" "Removing dir7/file1; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done" - dotest deep-rm5 "${testcvs} -q update -d -P" '' - dotest_fail deep-rm6 "test -d dir7" '' - - # Test rm -f -R. - cd ../.. - dotest deep-rm7 "${testcvs} rm -f -R dir5" \ -"${PROG} remove: Removing dir5 -${PROG} remove: scheduling .dir5/file1. for removal -${PROG} remove: Removing dir5/dir6 -${PROG} remove: scheduling .dir5/dir6/file1. for removal -${PROG} remove: use .${PROG} commit. to remove these files permanently" - dotest deep-rm8 "${testcvs} -q ci -m rm-it" \ -"Removing dir5/file1; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done -Removing dir5/dir6/file1; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done" - dotest deep-rm9 "${testcvs} -q update -d -P" '' - dotest_fail deep-rm10 "test -d dir5" - - cd ../../../../.. - - if echo "yes" | ${testcvs} release -d first-dir >>${LOGFILE}; then - pass deep-5 - else - fail deep-5 - fi - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - basic2) - # Test rtag, import, history, various miscellaneous operations - - # NOTE: this section has reached the size and - # complexity where it is getting to be a good idea to - # add new tests to a new section rather than - # continuing to piggyback them onto the tests here. - - # First empty the history file - rm ${CVSROOT_DIRNAME}/CVSROOT/history - touch ${CVSROOT_DIRNAME}/CVSROOT/history - -### XXX maybe should use 'cvs imprt -b1 -m new-module first-dir F F1' in an -### empty directory to do this instead of hacking directly into $CVSROOT - mkdir ${CVSROOT_DIRNAME}/first-dir - dotest basic2-1 "${testcvs} -q co first-dir" '' - for i in first-dir dir1 dir2 ; do - if test ! -d $i ; then - mkdir $i - dotest basic2-2-$i "${testcvs} add $i" \ -"Directory ${CVSROOT_DIRNAME}/.*/$i added to the repository" - fi - - cd $i - - for j in file6 file7; do - echo $j > $j - done - - dotest basic2-3-$i "${testcvs} add file6 file7" \ -"${PROG} add: scheduling file .file6. for addition -${PROG} add: scheduling file .file7. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - - done - cd ../../.. - dotest basic2-4 "${testcvs} update first-dir" \ -"${PROG} update: Updating first-dir -A first-dir/file6 -A first-dir/file7 -${PROG} update: Updating first-dir/dir1 -A first-dir/dir1/file6 -A first-dir/dir1/file7 -${PROG} update: Updating first-dir/dir1/dir2 -A first-dir/dir1/dir2/file6 -A first-dir/dir1/dir2/file7" - - # fixme: doesn't work right for added files. - dotest basic2-5 "${testcvs} log first-dir" \ -"${PROG} log: Logging first-dir -${PROG} log: file6 has been added, but not committed -${PROG} log: file7 has been added, but not committed -${PROG} log: Logging first-dir/dir1 -${PROG} log: file6 has been added, but not committed -${PROG} log: file7 has been added, but not committed -${PROG} log: Logging first-dir/dir1/dir2 -${PROG} log: file6 has been added, but not committed -${PROG} log: file7 has been added, but not committed" - - dotest basic2-6 "${testcvs} status first-dir" \ -"${PROG} status: Examining first-dir -=================================================================== -File: file6 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file7 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -${PROG} status: Examining first-dir/dir1 -=================================================================== -File: file6 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file7 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -${PROG} status: Examining first-dir/dir1/dir2 -=================================================================== -File: file6 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file7 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - -# XXX why is this commented out??? -# if ${CVS} diff -u first-dir >> ${LOGFILE} || test $? = 1 ; then -# pass 34 -# else -# fail 34 -# fi - - dotest basic2-8 "${testcvs} -q ci -m 'second dive' first-dir" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file6,v -done -Checking in first-dir/file6; -${CVSROOT_DIRNAME}/first-dir/file6,v <-- file6 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file7,v -done -Checking in first-dir/file7; -${CVSROOT_DIRNAME}/first-dir/file7,v <-- file7 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/file6,v -done -Checking in first-dir/dir1/file6; -${CVSROOT_DIRNAME}/first-dir/dir1/file6,v <-- file6 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/file7,v -done -Checking in first-dir/dir1/file7; -${CVSROOT_DIRNAME}/first-dir/dir1/file7,v <-- file7 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file6,v -done -Checking in first-dir/dir1/dir2/file6; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file6,v <-- file6 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v -done -Checking in first-dir/dir1/dir2/file7; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v <-- file7 -initial revision: 1\.1 -done" - - dotest basic2-9 "${testcvs} tag second-dive first-dir" \ -"${PROG} tag: Tagging first-dir -T first-dir/file6 -T first-dir/file7 -${PROG} tag: Tagging first-dir/dir1 -T first-dir/dir1/file6 -T first-dir/dir1/file7 -${PROG} tag: Tagging first-dir/dir1/dir2 -T first-dir/dir1/dir2/file6 -T first-dir/dir1/dir2/file7" - - # third dive - in bunch o' directories, add bunch o' files, - # delete some, change some. - - for i in first-dir dir1 dir2 ; do - cd $i - - # modify a file - echo file6 >>file6 - - # delete a file - rm file7 - - dotest basic2-10-$i "${testcvs} rm file7" \ -"${PROG} remove: scheduling .file7. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - - # and add a new file - echo file14 >file14 - - dotest basic2-11-$i "${testcvs} add file14" \ -"${PROG} add: scheduling file .file14. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - done - - cd ../../.. - dotest basic2-12 "${testcvs} update first-dir" \ -"${PROG} update: Updating first-dir -A first-dir/file14 -M first-dir/file6 -R first-dir/file7 -${PROG} update: Updating first-dir/dir1 -A first-dir/dir1/file14 -M first-dir/dir1/file6 -R first-dir/dir1/file7 -${PROG} update: Updating first-dir/dir1/dir2 -A first-dir/dir1/dir2/file14 -M first-dir/dir1/dir2/file6 -R first-dir/dir1/dir2/file7" - - # FIXME: doesn't work right for added files - dotest basic2-13 "${testcvs} log first-dir" \ -"${PROG} log: Logging first-dir -${PROG} log: file14 has been added, but not committed - -RCS file: ${CVSROOT_DIRNAME}/first-dir/file6,v -Working file: first-dir/file6 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - second-dive: 1\.1 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -second dive -============================================================================= - -RCS file: ${CVSROOT_DIRNAME}/first-dir/file7,v -Working file: first-dir/file7 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - second-dive: 1\.1 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -second dive -============================================================================= -${PROG} log: Logging first-dir/dir1 -${PROG} log: file14 has been added, but not committed - -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/file6,v -Working file: first-dir/dir1/file6 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - second-dive: 1\.1 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -second dive -============================================================================= - -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/file7,v -Working file: first-dir/dir1/file7 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - second-dive: 1\.1 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -second dive -============================================================================= -${PROG} log: Logging first-dir/dir1/dir2 -${PROG} log: file14 has been added, but not committed - -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file6,v -Working file: first-dir/dir1/dir2/file6 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - second-dive: 1\.1 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -second dive -============================================================================= - -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v -Working file: first-dir/dir1/dir2/file7 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - second-dive: 1\.1 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -second dive -=============================================================================" - - dotest basic2-14 "${testcvs} status first-dir" \ -"${PROG} status: Examining first-dir -=================================================================== -File: file14 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file6 Status: Locally Modified - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file6,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: no file file7 Status: Locally Removed - - Working revision: -1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file7,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -${PROG} status: Examining first-dir/dir1 -=================================================================== -File: file14 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file6 Status: Locally Modified - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/file6,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: no file file7 Status: Locally Removed - - Working revision: -1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/file7,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -${PROG} status: Examining first-dir/dir1/dir2 -=================================================================== -File: file14 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file6 Status: Locally Modified - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file6,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: no file file7 Status: Locally Removed - - Working revision: -1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - -# XXX why is this commented out? -# if ${CVS} diff -u first-dir >> ${LOGFILE} || test $? = 1 ; then -# pass 42 -# else -# fail 42 -# fi - - dotest basic2-16 "${testcvs} ci -m 'third dive' first-dir" \ -"${PROG} [a-z]*: Examining first-dir -${PROG} [a-z]*: Examining first-dir/dir1 -${PROG} [a-z]*: Examining first-dir/dir1/dir2 -RCS file: ${CVSROOT_DIRNAME}/first-dir/file14,v -done -Checking in first-dir/file14; -${CVSROOT_DIRNAME}/first-dir/file14,v <-- file14 -initial revision: 1\.1 -done -Checking in first-dir/file6; -${CVSROOT_DIRNAME}/first-dir/file6,v <-- file6 -new revision: 1\.2; previous revision: 1\.1 -done -Removing first-dir/file7; -${CVSROOT_DIRNAME}/first-dir/file7,v <-- file7 -new revision: delete; previous revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/file14,v -done -Checking in first-dir/dir1/file14; -${CVSROOT_DIRNAME}/first-dir/dir1/file14,v <-- file14 -initial revision: 1\.1 -done -Checking in first-dir/dir1/file6; -${CVSROOT_DIRNAME}/first-dir/dir1/file6,v <-- file6 -new revision: 1\.2; previous revision: 1\.1 -done -Removing first-dir/dir1/file7; -${CVSROOT_DIRNAME}/first-dir/dir1/file7,v <-- file7 -new revision: delete; previous revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file14,v -done -Checking in first-dir/dir1/dir2/file14; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file14,v <-- file14 -initial revision: 1\.1 -done -Checking in first-dir/dir1/dir2/file6; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file6,v <-- file6 -new revision: 1\.2; previous revision: 1\.1 -done -Removing first-dir/dir1/dir2/file7; -${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v <-- file7 -new revision: delete; previous revision: 1\.1 -done" - dotest basic2-17 "${testcvs} -q update first-dir" '' - - dotest basic2-18 "${testcvs} tag third-dive first-dir" \ -"${PROG} tag: Tagging first-dir -T first-dir/file14 -T first-dir/file6 -${PROG} tag: Tagging first-dir/dir1 -T first-dir/dir1/file14 -T first-dir/dir1/file6 -${PROG} tag: Tagging first-dir/dir1/dir2 -T first-dir/dir1/dir2/file14 -T first-dir/dir1/dir2/file6" - - dotest basic2-19 "echo yes | ${testcvs} release -d first-dir" \ -"You have \[0\] altered files in this repository\. -Are you sure you want to release (and delete) directory .first-dir.: " - - # end of third dive - dotest_fail basic2-20 "test -d first-dir" "" - - # now try some rtags - - # rtag HEADS - dotest basic2-21 "${testcvs} rtag rtagged-by-head first-dir" \ -"${PROG} rtag: Tagging first-dir -${PROG} rtag: Tagging first-dir/dir1 -${PROG} rtag: Tagging first-dir/dir1/dir2" - # The next test used to cause an assert failure - # something like: - # cvs: ./recurse.c:667: do_recursion: Assertion `repository != ((void *)0)' failed. - dotest basic2-21b "${testcvs} co -p -r rtagged-by-head first-dir/file6" \ -"=================================================================== -Checking out first-dir/file6 -RCS: $CVSROOT_DIRNAME/first-dir/file6,v -VERS: 1\.2 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -file6 -file6" - # tag by tag - dotest basic2-22 "${testcvs} rtag -r rtagged-by-head rtagged-by-tag first-dir" \ -"${PROG} rtag: Tagging first-dir -${PROG} rtag: Tagging first-dir/dir1 -${PROG} rtag: Tagging first-dir/dir1/dir2" - - # tag by revision - dotest basic2-23 "${testcvs} rtag -r1.1 rtagged-by-revision first-dir" \ -"${PROG} rtag: Tagging first-dir -${PROG} rtag: Tagging first-dir/dir1 -${PROG} rtag: Tagging first-dir/dir1/dir2" - - # rdiff by revision - dotest basic2-24 "${testcvs} rdiff -r1.1 -rrtagged-by-head first-dir" \ -"${PROG} rdiff: Diffing first-dir -Index: first-dir/file6 -diff -c first-dir/file6:1\.1 first-dir/file6:1\.2 -\*\*\* first-dir/file6:1\.1 ${DATE} ---- first-dir/file6 ${DATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* ---- 1,2 ---- - file6 -${PLUS} file6 -Index: first-dir/file7 -diff -c first-dir/file7:1\.1 first-dir/file7:removed -\*\*\* first-dir/file7:1.1 ${DATE} ---- first-dir/file7 ${DATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -- file7 ---- 0 ---- -${PROG} rdiff: Diffing first-dir/dir1 -Index: first-dir/dir1/file6 -diff -c first-dir/dir1/file6:1\.1 first-dir/dir1/file6:1\.2 -\*\*\* first-dir/dir1/file6:1\.1 ${DATE} ---- first-dir/dir1/file6 ${DATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* ---- 1,2 ---- - file6 -${PLUS} file6 -Index: first-dir/dir1/file7 -diff -c first-dir/dir1/file7:1\.1 first-dir/dir1/file7:removed -\*\*\* first-dir/dir1/file7:1\.1 ${DATE} ---- first-dir/dir1/file7 ${DATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -- file7 ---- 0 ---- -${PROG} rdiff: Diffing first-dir/dir1/dir2 -Index: first-dir/dir1/dir2/file6 -diff -c first-dir/dir1/dir2/file6:1\.1 first-dir/dir1/dir2/file6:1\.2 -\*\*\* first-dir/dir1/dir2/file6:1\.1 ${DATE} ---- first-dir/dir1/dir2/file6 ${DATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* ---- 1,2 ---- - file6 -${PLUS} file6 -Index: first-dir/dir1/dir2/file7 -diff -c first-dir/dir1/dir2/file7:1\.1 first-dir/dir1/dir2/file7:removed -\*\*\* first-dir/dir1/dir2/file7:1\.1 ${DATE} ---- first-dir/dir1/dir2/file7 ${DATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -- file7 ---- 0 ----" - dotest basic2-24a "${testcvs} rdiff -l -r1.1 -rrtagged-by-head first-dir" \ -"${PROG} rdiff: Diffing first-dir -Index: first-dir/file6 -diff -c first-dir/file6:1\.1 first-dir/file6:1\.2 -\*\*\* first-dir/file6:1\.1 ${DATE} ---- first-dir/file6 ${DATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* ---- 1,2 ---- - file6 -${PLUS} file6 -Index: first-dir/file7 -diff -c first-dir/file7:1\.1 first-dir/file7:removed -\*\*\* first-dir/file7:1.1 ${DATE} ---- first-dir/file7 ${DATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -- file7 ---- 0 ----" - # now export by rtagged-by-head and rtagged-by-tag and compare. - dotest basic2-25 "${testcvs} export -r rtagged-by-head -d 1dir first-dir" \ -"${PROG} export: Updating 1dir -U 1dir/file14 -U 1dir/file6 -${PROG} export: Updating 1dir/dir1 -U 1dir/dir1/file14 -U 1dir/dir1/file6 -${PROG} export: Updating 1dir/dir1/dir2 -U 1dir/dir1/dir2/file14 -U 1dir/dir1/dir2/file6" - dotest_fail basic2-25a "test -d 1dir/CVS" - dotest_fail basic2-25b "test -d 1dir/dir1/CVS" - dotest_fail basic2-25c "test -d 1dir/dir1/dir2/CVS" - - dotest basic2-26 "${testcvs} export -r rtagged-by-tag first-dir" \ -"${PROG} export: Updating first-dir -U first-dir/file14 -U first-dir/file6 -${PROG} export: Updating first-dir/dir1 -U first-dir/dir1/file14 -U first-dir/dir1/file6 -${PROG} export: Updating first-dir/dir1/dir2 -U first-dir/dir1/dir2/file14 -U first-dir/dir1/dir2/file6" - dotest_fail basic2-26a "test -d first-dir/CVS" - dotest_fail basic2-26b "test -d first-dir/dir1/CVS" - dotest_fail basic2-26c "test -d first-dir/dir1/dir2/CVS" - - dotest basic2-27 "directory_cmp 1dir first-dir" - rm -r 1dir first-dir - - # checkout by revision vs export by rtagged-by-revision and compare. - mkdir export-dir - dotest basic2-28 "${testcvs} export -rrtagged-by-revision -d export-dir first-dir" \ -"${PROG} export: Updating export-dir -U export-dir/file14 -U export-dir/file6 -U export-dir/file7 -${PROG} export: Updating export-dir/dir1 -U export-dir/dir1/file14 -U export-dir/dir1/file6 -U export-dir/dir1/file7 -${PROG} export: Updating export-dir/dir1/dir2 -U export-dir/dir1/dir2/file14 -U export-dir/dir1/dir2/file6 -U export-dir/dir1/dir2/file7" - dotest_fail basic2-28a "test -d export-dir/CVS" - dotest_fail basic2-28b "test -d export-dir/dir1/CVS" - dotest_fail basic2-28c "test -d export-dir/dir1/dir2/CVS" - - dotest basic2-29 "${testcvs} co -r1.1 first-dir" \ -"${PROG} checkout: Updating first-dir -U first-dir/file14 -U first-dir/file6 -U first-dir/file7 -${PROG} checkout: Updating first-dir/dir1 -U first-dir/dir1/file14 -U first-dir/dir1/file6 -U first-dir/dir1/file7 -${PROG} checkout: Updating first-dir/dir1/dir2 -U first-dir/dir1/dir2/file14 -U first-dir/dir1/dir2/file6 -U first-dir/dir1/dir2/file7" - - # directory copies are done in an oblique way in order to avoid a bug in sun's tmp filesystem. - mkdir first-dir.cpy ; (cd first-dir ; tar cf - . | (cd ../first-dir.cpy ; tar xf -)) - - dotest basic2-30 "directory_cmp first-dir export-dir" - - # interrupt, while we've got a clean 1.1 here, let's import it - # into a couple of other modules. - cd export-dir - dotest_sort basic2-31 "${testcvs} import -m first-import second-dir first-immigration immigration1 immigration1_0" \ -" - -N second-dir/dir1/dir2/file14 -N second-dir/dir1/dir2/file6 -N second-dir/dir1/dir2/file7 -N second-dir/dir1/file14 -N second-dir/dir1/file6 -N second-dir/dir1/file7 -N second-dir/file14 -N second-dir/file6 -N second-dir/file7 -No conflicts created by this import -${PROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/dir1 -${PROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/dir1/dir2" - cd .. - - dotest basic2-32 "${testcvs} export -r HEAD second-dir" \ -"${PROG} export: Updating second-dir -U second-dir/file14 -U second-dir/file6 -U second-dir/file7 -${PROG} export: Updating second-dir/dir1 -U second-dir/dir1/file14 -U second-dir/dir1/file6 -U second-dir/dir1/file7 -${PROG} export: Updating second-dir/dir1/dir2 -U second-dir/dir1/dir2/file14 -U second-dir/dir1/dir2/file6 -U second-dir/dir1/dir2/file7" - - dotest basic2-33 "directory_cmp first-dir second-dir" - - rm -r second-dir - - rm -r export-dir first-dir - mkdir first-dir - (cd first-dir.cpy ; tar cf - . | (cd ../first-dir ; tar xf -)) - - # update the top, cancelling sticky tags, retag, update other copy, compare. - cd first-dir - dotest basic2-34 "${testcvs} update -A -l *file*" \ -"[UP] file6 -${PROG} update: file7 is no longer in the repository" - - # If we don't delete the tag first, cvs won't retag it. - # This would appear to be a feature. - dotest basic2-35 "${testcvs} tag -l -d rtagged-by-revision" \ -"${PROG} tag: Untagging \. -D file14 -D file6" - dotest basic2-36 "${testcvs} tag -l rtagged-by-revision" \ -"${PROG} tag: Tagging \. -T file14 -T file6" - - cd .. - mv first-dir 1dir - mv first-dir.cpy first-dir - cd first-dir - - dotest basic2-37 "${testcvs} -q diff -u" '' - - dotest basic2-38 "${testcvs} update" \ -"${PROG} update: Updating . -${PROG} update: Updating dir1 -${PROG} update: Updating dir1/dir2" - - cd .. - - #### FIXME: is this expected to work??? Need to investigate - #### and fix or remove the test. -# dotest basic2-39 "directory_cmp 1dir first-dir" - - rm -r 1dir first-dir - - # Test the cvs history command. - - # The reason that there are two patterns rather than using - # \(${TESTDIR}\|<remote>\) is that we are trying to - # make this portable. Perhaps at some point we should - # ditch that notion and require GNU expr (or dejagnu or....) - # since it seems to be so painful. - - # why are there two lines at the end of the local output - # which don't exist in the remote output? would seem to be - # a CVS bug. - dotest basic2-64 "${testcvs} his -x TOFWUPCGMAR -a" \ -"O [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir =first-dir= ${TESTDIR}/\* -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir == ${TESTDIR} -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir == ${TESTDIR} -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1 == ${TESTDIR} -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1 == ${TESTDIR} -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1/dir2 == ${TESTDIR} -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1/dir2 == ${TESTDIR} -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir == ${TESTDIR} -M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == ${TESTDIR} -R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir == ${TESTDIR} -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1 == ${TESTDIR} -M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1 == ${TESTDIR} -R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1 == ${TESTDIR} -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1/dir2 == ${TESTDIR} -M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1/dir2 == ${TESTDIR} -R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1/dir2 == ${TESTDIR} -F [0-9-]* [0-9:]* ${PLUS}0000 ${username} =first-dir= ${TESTDIR}/\* -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= ${TESTDIR}/\* -U [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == ${TESTDIR}/first-dir -W [0-9-]* [0-9:]* ${PLUS}0000 ${username} file7 first-dir == ${TESTDIR}/first-dir" \ -"O [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir =first-dir= <remote>/\* -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir == <remote> -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir == <remote> -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1 == <remote> -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1 == <remote> -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1/dir2 == <remote> -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1/dir2 == <remote> -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir == <remote> -M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == <remote> -R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir == <remote> -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1 == <remote> -M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1 == <remote> -R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1 == <remote> -A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1/dir2 == <remote> -M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1/dir2 == <remote> -R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1/dir2 == <remote> -F [0-9-]* [0-9:]* ${PLUS}0000 ${username} =first-dir= <remote>/\* -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= <remote>/\* -P [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == <remote> -W [0-9-]* [0-9:]* ${PLUS}0000 ${username} file7 first-dir == <remote>" - - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -rf ${CVSROOT_DIRNAME}/second-dir - ;; - - parseroot) - mkdir 1; cd 1 - # Test odd cases involving CVSROOT. At the moment, that means we - # are testing roots with '/'s on the end, which CVS should parse off. - CVSROOT_save=${CVSROOT} - CVSROOT="${CVSROOT}/////" - dotest parseroot-1 "${testcvs} -q co CVSROOT/modules" \ -"U CVSROOT/modules" - dotest parseroot-2 "${testcvs} -q ci -fmnull-change CVSROOT/modules" \ -"Checking in CVSROOT/modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.2; previous revision: 1\.1 -done -${PROG} commit: Rebuilding administrative file database" - - if $remote; then - # I only test these when testing remote in case CVS was compiled - # without client support. - - # logout does not try to contact the server. - CVSROOT=":pserver;proxy=localhost;proxyport=8080:localhost/dev/null" - dotest parseroot-3r "$testcvs -d'$CVSROOT' logout" \ -"$PROG logout: WARNING: Ignoring method options found in CVSROOT: \`proxy=localhost;proxyport=8080'\. -$PROG logout: Use CVS version 1\.12\.7 or later to handle method options\. -Logging out of :pserver:$username@localhost:2401/dev/null -$PROG logout: warning: failed to open $HOME/\.cvspass for reading: No such file or directory -$PROG logout: Entry not found\." - fi - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - CVSROOT=$CVSROOT_save - cd .. - rm -r 1 - ;; - - - - files) - # Test of how we specify files on the command line - # (recurse.c and that sort of thing). Vaguely similar to - # tests like basic* and deep. See modules and such tests - # for what happens when we throw in modules and co -d, &c. - - # This particular test is fairly carefully crafted, to spot - # one particular issue with remote. - mkdir 1; cd 1 - dotest files-1 "${testcvs} -q co -l ." "" - mkdir first-dir - dotest files-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch tfile - dotest files-3 "${testcvs} add tfile" \ -"${PROG} add: scheduling file .tfile. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest files-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/tfile,v -done -Checking in tfile; -${CVSROOT_DIRNAME}/first-dir/tfile,v <-- tfile -initial revision: 1\.1 -done" - dotest files-5 "${testcvs} -q tag -b C" "T tfile" - dotest files-6 "$testcvs -q update -r C" "U tfile" - mkdir dir - dotest files-7 "${testcvs} add dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir added to the repository ---> Using per-directory sticky tag .C'" - cd dir - touch .file - dotest files-6 "${testcvs} add .file" \ -"${PROG} add: scheduling file .\.file' for addition on branch .C. -${PROG} add: use .${PROG} commit. to add this file permanently" - mkdir sdir - dotest files-7 "${testcvs} add sdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir/sdir added to the repository ---> Using per-directory sticky tag .C'" - cd sdir - mkdir ssdir - dotest files-8 "${testcvs} add ssdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir added to the repository ---> Using per-directory sticky tag .C'" - cd ssdir - touch .file - dotest files-9 "${testcvs} add .file" \ -"${PROG} add: scheduling file .\.file' for addition on branch .C. -${PROG} add: use .${PROG} commit. to add this file permanently" - cd ../.. - dotest files-10 "${testcvs} -q ci -m test" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v -done -Checking in \.file; -${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v <-- \.file -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v -done -Checking in sdir/ssdir/\.file; -${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - dotest files-11 \ -"${testcvs} commit -m test -f ./.file ./sdir/ssdir/.file" \ -"Checking in \.file; -${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v <-- \.file -new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 -done -Checking in \./sdir/ssdir/\.file; -${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file -new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 -done" - if $remote; then - # FIXCVS: - # This is a bug, looks like that toplevel_repos cruft in - # client.c is coming back to haunt us. - # May want to think about the whole issue, toplevel_repos - # has always been crufty and trying to patch it up again - # might be a mistake. - dotest files-12 \ -"${testcvs} commit -f -m test ./sdir/ssdir/.file ./.file" \ -"Checking in \./sdir/ssdir/\.file; -${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file -new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2 -done" - - # Sync up the version numbers so that the rest of the - # tests don't need to expect different numbers based - # local or remote. - dotest files-12-workaround \ -"${testcvs} commit -f -m test .file" \ -"Checking in \.file; -${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v <-- \.file -new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2 -done" - else - dotest files-12 \ -"${testcvs} commit -f -m test ./sdir/ssdir/.file ./.file" \ -"Checking in \./sdir/ssdir/\.file; -${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file -new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2 -done -Checking in \.file; -${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v <-- \.file -new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2 -done" - fi - dotest files-13 \ -"${testcvs} commit -fmtest ./sdir/../sdir/ssdir/..///ssdir/.file" \ -"Checking in \./sdir/\.\./sdir/ssdir/\.\.///ssdir/\.file; -${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file -new revision: 1\.1\.2\.4; previous revision: 1\.1\.2\.3 -done" - if $remote; then - dotest files-14 \ -"${testcvs} commit -fmtest ../../first-dir/dir/.file" \ -"Checking in \.\./\.\./first-dir/dir/\.file; -${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v <-- .file -new revision: 1\.1\.2\.4; previous revision: 1\.1\.2\.3 -done" - else - dotest files-14 \ -"${testcvs} commit -fmtest ../../first-dir/dir/.file" \ -"Checking in \.\./\.\./first-dir/dir/\.file; -${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v <-- \.file -new revision: 1\.1\.2\.4; previous revision: 1\.1\.2\.3 -done" - fi - cd ../../.. - - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - spacefiles) - # More filename tests, in particular spaces in file names. - # (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). - - mkdir 1; cd 1 - dotest spacefiles-1 "${testcvs} -q co -l ." "" - touch ./-c - dotest spacefiles-2 "${testcvs} add -- -c" \ -"${PROG} add: scheduling file .-c. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest spacefiles-3 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/-c,v -done -Checking in -c; -${CVSROOT_DIRNAME}/-c,v <-- -c -initial revision: 1\.1 -done" - mkdir 'first dir' - dotest spacefiles-4 "${testcvs} add 'first dir'" \ -"Directory ${CVSROOT_DIRNAME}/first dir added to the repository" - mkdir ./-b - dotest spacefiles-5 "${testcvs} add -- -b" \ -"Directory ${CVSROOT_DIRNAME}/-b added to the repository" - cd 'first dir' - touch 'a file' - dotest spacefiles-6 "${testcvs} add 'a file'" \ -"${PROG} add: scheduling file .a file. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest spacefiles-7 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first dir/a file,v -done -Checking in a file; -${CVSROOT_DIRNAME}/first dir/a file,v <-- a file -initial revision: 1\.1 -done" - dotest spacefiles-8 "${testcvs} -q tag new-tag" "T a file" - cd ../.. - - mkdir 2; cd 2 - dotest spacefiles-10 "${testcvs} co -- -b" \ -"${PROG} checkout: Updating -b" - dotest spacefiles-11 "${testcvs} -q co -- -c" "U \./-c" - rm ./-c - dotest spacefiles-13 "${testcvs} -q co 'first dir'" \ -"U first dir/a file" - cd .. - - mkdir 3; cd 3 - dotest spacefiles-14 "${testcvs} -q co 'first dir/a file'" \ -"U first dir/a file" - cd .. - - rm -r 1 2 3 - rm -rf "${CVSROOT_DIRNAME}/first dir" - rm -r ${CVSROOT_DIRNAME}/-b - rm -f ${CVSROOT_DIRNAME}/-c,v - ;; - - commit-readonly) - mkdir 1; cd 1 - module=x - - : > junk - dotest commit-readonly-1 "$testcvs -Q import -m . $module X Y" '' - dotest commit-readonly-2 "$testcvs -Q co $module" '' - cd $module - - file=m - - # Include an rcs keyword to be expanded. - echo '$Id''$' > $file - - dotest commit-readonly-3 "$testcvs add $file" \ -"${PROG} add: scheduling file .$file. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest commit-readonly-4 "$testcvs -Q ci -m . $file" \ -"RCS file: ${CVSROOT_DIRNAME}/$module/$file,v -done -Checking in $file; -${CVSROOT_DIRNAME}/$module/$file,v <-- $file -initial revision: 1\.1 -done" - - echo line2 >> $file - # Make the file read-only. - chmod a-w $file - - dotest commit-readonly-5 "$testcvs -Q ci -m . $file" \ -"Checking in $file; -${CVSROOT_DIRNAME}/$module/$file,v <-- $file -new revision: 1\.2; previous revision: 1\.1 -done" - - cd ../.. - rm -rf 1 - rm -rf ${CVSROOT_DIRNAME}/$module - ;; - - status) - # This tests for a bug in the status command which failed to - # notice resolved conflicts. - mkdir status; cd status - dotest status-init-1 "${testcvs} -q co -l ." "" - mkdir first-dir - dotest status-init-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - echo a line >tfile - dotest status-init-3 "${testcvs} add tfile" \ -"${PROG} add: scheduling file .tfile. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest status-init-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/tfile,v -done -Checking in tfile; -${CVSROOT_DIRNAME}/first-dir/tfile,v <-- tfile -initial revision: 1\.1 -done" - cd .. - dotest status-init-5 "${testcvs} -q co -dsecond-dir first-dir" \ -"U second-dir/tfile" - cd second-dir - echo some junk >>tfile - dotest status-init-6 "${testcvs} -q ci -maline" \ -"Checking in tfile; -${CVSROOT_DIRNAME}/first-dir/tfile,v <-- tfile -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../first-dir - echo force a conflict >>tfile - dotest status-init-7 "${testcvs} -q up" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/tfile,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into tfile -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in tfile -C tfile" - - # Now note our status - dotest status-1 "${testcvs} status tfile" \ -"=================================================================== -File: tfile Status: Unresolved Conflict - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/tfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - - # touch the file, leaving conflict markers in place - # and note our status - touch tfile - dotest status-2 "${testcvs} status tfile" \ -"=================================================================== -File: tfile Status: File had conflicts on merge - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/tfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - - # resolve the conflict - echo resolution >tfile - dotest status-3 "${testcvs} status tfile" \ -"=================================================================== -File: tfile Status: Locally Modified - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/tfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - - # Check that there are no problems just using CVS/Root too. - save_CVSROOT=$CVSROOT - unset CVSROOT - dotest status-3a "${testcvs} status tfile" \ -"=================================================================== -File: tfile Status: Locally Modified - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/tfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - CVSROOT=$save_CVSROOT - export CVSROOT - - # FIXCVS: - # Update is supposed to re-Register() the file when it - # finds resolved conflicts: - dotest status-4 "grep 'Result of merge' CVS/Entries" \ -"/tfile/1\.2/Result of merge${PLUS}[a-zA-Z0-9 :]*//" - - cd .. - mkdir fourth-dir - dotest status-init-8 "$testcvs add fourth-dir" \ -"Directory $CVSROOT_DIRNAME/fourth-dir added to the repository" - cd fourth-dir - echo yet another line >t3file - dotest status-init-9 "$testcvs add t3file" \ -"$PROG add: scheduling file .t3file. for addition -$PROG add: use .$PROG commit. to add this file permanently" - dotest status-init-10 "$testcvs -q ci -m add" \ -"RCS file: $CVSROOT_DIRNAME/fourth-dir/t3file,v -done -Checking in t3file; -$CVSROOT_DIRNAME/fourth-dir/t3file,v <-- t3file -initial revision: 1\.1 -done" - cd ../first-dir - mkdir third-dir - dotest status-init-11 "$testcvs add third-dir" \ -"Directory $CVSROOT_DIRNAME/first-dir/third-dir added to the repository" - cd third-dir - echo another line >t2file - dotest status-init-12 "$testcvs add t2file" \ -"$PROG add: scheduling file .t2file. for addition -$PROG add: use .$PROG commit. to add this file permanently" - dotest status-init-13 "$testcvs -q ci -m add" \ -"RCS file: $CVSROOT_DIRNAME/first-dir/third-dir/t2file,v -done -Checking in t2file; -$CVSROOT_DIRNAME/first-dir/third-dir/t2file,v <-- t2file -initial revision: 1\.1 -done" - dotest status-5 "$testcvs status ../tfile" \ -"=================================================================== -File: tfile Status: Locally Modified - - Working revision: 1\.2.* - Repository revision: 1\.2 $CVSROOT_DIRNAME/first-dir/tfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest status-6 "$testcvs status ../../fourth-dir/t3file" \ -"=================================================================== -File: t3file Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 $CVSROOT_DIRNAME/fourth-dir/t3file,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd ../../.. - rm -rf status - rm -rf $CVSROOT_DIRNAME/first-dir $CVSROOT_DIRNAME/fourth-dir - ;; - - rdiff) - # Test rdiff - # XXX for now this is just the most essential test... - cd ${TESTDIR} - - mkdir testimport - cd testimport - echo '$''Id$' > foo - echo '$''Name$' >> foo - echo '$''Id$' > bar - echo '$''Name$' >> bar - dotest_sort rdiff-1 \ - "${testcvs} import -I ! -m test-import-with-keyword trdiff TRDIFF T1" \ -' - -N trdiff/bar -N trdiff/foo -No conflicts created by this import' - dotest rdiff-2 \ - "${testcvs} co -ko trdiff" \ -"${PROG} checkout: Updating trdiff -U trdiff/bar -U trdiff/foo" - cd trdiff - echo something >> foo - dotest rdiff-3 \ - "${testcvs} ci -m added-something foo" \ -"Checking in foo; -${CVSROOT_DIRNAME}/trdiff/foo,v <-- foo -new revision: 1\.2; previous revision: 1\.1 -done" - echo '#ident "@(#)trdiff:$''Name$:$''Id$"' > new - echo "new file" >> new - dotest rdiff-4 \ - "${testcvs} add -m new-file-description new" \ -"${PROG} add: scheduling file \`new' for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest rdiff-5 \ - "${testcvs} commit -m added-new-file new" \ -"RCS file: ${CVSROOT_DIRNAME}/trdiff/new,v -done -Checking in new; -${CVSROOT_DIRNAME}/trdiff/new,v <-- new -initial revision: 1\.1 -done" - dotest rdiff-6 \ - "${testcvs} tag local-v0" \ -"${PROG} tag: Tagging . -T bar -T foo -T new" - dotest rdiff-7 \ - "${testcvs} status -v foo" \ -"=================================================================== -File: foo Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/trdiff/foo,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -ko - - Existing Tags: - local-v0 (revision: 1\.2) - T1 (revision: 1\.1\.1\.1) - TRDIFF (branch: 1\.1\.1)" - - cd .. - rm -r trdiff - - dotest rdiff-8 \ - "${testcvs} rdiff -r T1 -r local-v0 trdiff" \ -"${PROG}"' rdiff: Diffing trdiff -Index: trdiff/foo -diff -c trdiff/foo:1\.1\.1\.1 trdiff/foo:1\.2 -\*\*\* trdiff/foo:1\.1\.1\.1 '"${DATE}"' ---- trdiff/foo '"${DATE}"' -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1,2 \*\*\*\* -! \$''Id: foo,v 1\.1\.1\.1 [0-9/]* [0-9:]* '"${username}"' Exp \$ -! \$''Name: T1 \$ ---- 1,3 ---- -! \$''Id: foo,v 1\.2 [0-9/]* [0-9:]* '"${username}"' Exp \$ -! \$''Name: local-v0 \$ -! something -Index: trdiff/new -diff -c /dev/null trdiff/new:1\.1 -\*\*\* /dev/null '"${DATE}"' ---- trdiff/new '"${DATE}"' -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 0 \*\*\*\* ---- 1,2 ---- -'"${PLUS}"' #ident "@(#)trdiff:\$''Name: local-v0 \$:\$''Id: new,v 1\.1 [0-9/]* [0-9:]* '"${username}"' Exp \$" -'"${PLUS}"' new file' - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd .. - rm -r testimport - rm -rf ${CVSROOT_DIRNAME}/trdiff - ;; - - rdiff-short) - # Test that the short patch behaves as expected - # 1) Added file. - # 2) Removed file. - # 3) Different revision number with no difference. - # 4) Different revision number with changes. - # 5) Against trunk. - # 6) Same revision number (no difference). - mkdir rdiff-short; cd rdiff-short - mkdir abc - dotest rdiff-short-init-1 \ -"${testcvs} -q import -I ! -m initial-import abc vendor initial" \ -' -No conflicts created by this import' - - dotest rdiff-short-init-2 "${testcvs} -q get abc" '' - cd abc - echo "abc" >file1.txt - dotest rdiff-short-init-3 "${testcvs} add file1.txt" \ -"${PROG} add: scheduling file .file1\.txt' for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest rdiff-short-init-4 \ -"${testcvs} commit -madd-file1 file1.txt" \ -"RCS file: ${CVSROOT_DIRNAME}/abc/file1\.txt,v -done -Checking in file1\.txt; -${CVSROOT_DIRNAME}/abc/file1\.txt,v <-- file1\.txt -initial revision: 1\.1 -done" - echo def >>file1.txt - dotest rdiff-short-init-5 \ -"${testcvs} commit -mchange-file1 file1.txt" \ -"Checking in file1\.txt; -${CVSROOT_DIRNAME}/abc/file1\.txt,v <-- file1\.txt -new revision: 1\.2; previous revision: 1\.1 -done" - echo "abc" >file1.txt - dotest rdiff-short-init-6 \ -"${testcvs} commit -mrestore-file1-rev1 file1.txt" \ -"Checking in file1\.txt; -${CVSROOT_DIRNAME}/abc/file1\.txt,v <-- file1\.txt -new revision: 1\.3; previous revision: 1\.2 -done" - dotest rdiff-short-init-7 \ -"${testcvs} tag -r 1.1 tag1 file1.txt" \ -"T file1\.txt" - dotest rdiff-short-init-8 \ -"${testcvs} tag -r 1.2 tag2 file1.txt" \ -"T file1\.txt" - dotest rdiff-short-init-9 \ -"${testcvs} tag -r 1.3 tag3 file1.txt" \ -"T file1\.txt" - echo "abc" >file2.txt - dotest rdiff-short-init-10 \ -"${testcvs} add file2.txt" \ -"${PROG} add: scheduling file .file2\.txt' for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest rdiff-add-remove-nodiff-init-11 \ -"${testcvs} commit -madd-file2 file2.txt" \ -"RCS file: ${CVSROOT_DIRNAME}/abc/file2\.txt,v -done -Checking in file2\.txt; -${CVSROOT_DIRNAME}/abc/file2\.txt,v <-- file2\.txt -initial revision: 1\.1 -done" - dotest rdiff-short-init-12 \ -"${testcvs} tag -r 1.1 tag4 file2.txt" \ -"T file2\.txt" - dotest rdiff-short-init-13 \ -"${testcvs} tag -r 1.1 tag5 file2.txt" \ -"T file2\.txt" - cd ../.. - rm -fr rdiff-short - - # 3) Different revision number with no difference. - dotest rdiff-short-no-real-change \ -"${testcvs} -q rdiff -s -r tag1 -r tag3 abc" - - # 4) Different revision number with changes. - dotest rdiff-short-real-change \ -"${testcvs} -q rdiff -s -r tag1 -r tag2 abc" \ -'File abc/file1.txt changed from revision 1\.1 to 1\.2' - - # 1) Added file. - # 2) Removed file. - dotest_sort rdiff-short-remove-add \ -"${testcvs} -q rdiff -s -r tag2 -r tag4 abc" \ -'File abc/file1\.txt is removed; tag2 revision 1\.2 -File abc/file2\.txt is new; tag4 revision 1\.1' - - # 6) Same revision number (no difference). - dotest rdiff-short-no-change \ -"${testcvs} -q rdiff -s -r tag4 -r tag5 abc" - - # 5) Against trunk. - # Check that the messages change when we diff against the trunk - # rather than a tag or date. - dotest rdiff-short-against-trunk-1 \ -"${testcvs} -q rdiff -s -rtag4 abc" \ -"File abc/file1\.txt is new; current revision 1\.3" - - dotest rdiff-short-against-trunk-2 \ -"${testcvs} -q rdiff -s -rtag2 abc" \ -"File abc/file1\.txt changed from revision 1\.2 to 1\.3 -File abc/file2\.txt is new; current revision 1\.1" - - rm -rf ${CVSROOT_DIRNAME}/abc - ;; - - rdiff2) - # Test for the segv problem reported by James Cribb - # Somewhere to work - mkdir rdiff2; cd rdiff2 - # Create a module "m" with files "foo" and "d/bar" - mkdir m; cd m - echo foo >foo - mkdir d - echo bar >d/bar - dotest_sort rdiff2-1 \ -"${testcvs} -q import -I ! -m initial-import m vendor initial" \ -' - -N m/d/bar -N m/foo -No conflicts created by this import' - - cd .. - rm -r m - - # Remove "foo" - dotest rdiff2-2 "${testcvs} get m" \ -"${PROG} checkout: Updating m -U m/foo -${PROG} checkout: Updating m/d -U m/d/bar" - cd m - dotest rdiff2-3 "${testcvs} rm -f foo" \ -"${PROG} remove: scheduling .foo. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - - dotest rdiff2-4 "${testcvs} commit -m Removed foo" \ -"Removing foo; -${CVSROOT_DIRNAME}/m/foo,v <-- foo -new revision: delete; previous revision: 1\.1\.1\.1 -done" - - # Modify "d/bar" - echo foo >d/bar - dotest rdiff2-5 "${testcvs} commit -m Changed d/bar" \ -"Checking in d/bar; -${CVSROOT_DIRNAME}/m/d/bar,v <-- bar -new revision: 1\.2; previous revision: 1\.1 -done" - - # Crash before showing d/bar diffs - dotest_fail rdiff2-6 "${testcvs} rdiff -t m" \ -"${PROG} rdiff: Diffing m -${PROG} rdiff: Diffing m/d -Index: m/d/bar -diff -c m/d/bar:1\.1\.1\.1 m/d/bar:1\.2 -\*\*\* m/d/bar:1\.1\.1\.1 ${DATE} ---- m/d/bar ${DATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -! bar ---- 1 ---- -! foo" - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - cd ../.. - rm -rf rdiff2 - rm -rf ${CVSROOT_DIRNAME}/m - ;; - - diff) - # Various tests specific to the "cvs diff" command. - # Related tests: - # death2: -N - # rcslib: cvs diff and $Name. - # rdiff: cvs rdiff. - # diffmerge*: nuts and bolts (stuff within diff library) - mkdir 1; cd 1 - dotest diff-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest diff-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - # diff is anomalous. Most CVS commands print the "nothing - # known" message (or worse yet, no message in some cases) but - # diff says "I know nothing". Shrug. - dotest_fail diff-3 "${testcvs} diff xyzpdq" \ -"${PROG} diff: I know nothing about xyzpdq" - touch abc - dotest diff-4 "${testcvs} add abc" \ -"${PROG} add: scheduling file .abc. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest diff-5 "${testcvs} -q ci -mtest" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -done -Checking in abc; -${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc -initial revision: 1\.1 -done" - echo "extern int gethostname ();" >abc - dotest diff-6 "${testcvs} -q ci -mtest" \ -"Checking in abc; -${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc -new revision: 1\.2; previous revision: 1\.1 -done" - echo "#include <winsock.h>" >abc - # check the behavior of the --ifdef=MACRO option - dotest_fail diff-7 "${testcvs} -q diff --ifdef=HAVE_WINSOCK_H" \ -"Index: abc -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -retrieving revision 1\.2 -diff --ifdef HAVE_WINSOCK_H -r1\.2 abc -#ifndef HAVE_WINSOCK_H -extern int gethostname (); -#else /\* HAVE_WINSOCK_H \*/ -#include <winsock\.h> -#endif /\* HAVE_WINSOCK_H \*/" - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd ../.. - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -r 1 - ;; - - diffnl) - # Test handling of 'cvs diff' of files without newlines - mkdir 1; cd 1 - dotest diffnl-000 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest diffnl-001 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nfive\nsix")}' </dev/null >abc - dotest diffnl-002 "${testcvs} add abc" \ -"${PROG} add: scheduling file .abc. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest diffnl-003 "${testcvs} -q ci -mtest" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -done -Checking in abc; -${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc -initial revision: 1\.1 -done" - - # change to line near EOF - ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nsix")}' </dev/null >abc - dotest_fail diffnl-100 "${testcvs} diff abc" \ -"Index: abc -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -retrieving revision 1\.1 -diff -r1\.1 abc -5d4 -< five" - dotest_fail diffnl-101 "${testcvs} diff -u abc" \ -"Index: abc -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -retrieving revision 1\.1 -diff -u -r1\.1 abc ---- abc ${RFCDATE} 1\.1 -+++ abc ${RFCDATE} -@@ -2,5 +2,4 @@ - two - three - four --five - six -\\\\ No newline at end of file" - dotest diffnl-102 "${testcvs} -q ci -mtest abc" \ -"Checking in abc; -${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc -new revision: 1\.2; previous revision: 1\.1 -done" - - # Change to last line - ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nseven")}' </dev/null >abc - dotest_fail diffnl-200 "${testcvs} diff abc" \ -"Index: abc -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -retrieving revision 1\.2 -diff -r1\.2 abc -5c5 -< six -\\\\ No newline at end of file ---- -> seven -\\\\ No newline at end of file" - dotest_fail diffnl-201 "${testcvs} diff -u abc" \ -"Index: abc -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -retrieving revision 1\.2 -diff -u -r1\.2 abc ---- abc ${RFCDATE} 1\.2 -+++ abc ${RFCDATE} -@@ -2,4 +2,4 @@ - two - three - four --six -\\\\ No newline at end of file -+seven -\\\\ No newline at end of file" - dotest diffnl-202 "${testcvs} ci -mtest abc" \ -"Checking in abc; -${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc -new revision: 1\.3; previous revision: 1\.2 -done" - - # Addition of newline - echo "one -two -three -four -seven" > abc - dotest_fail diffnl-300 "${testcvs} diff abc" \ -"Index: abc -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -retrieving revision 1\.3 -diff -r1\.3 abc -5c5 -< seven -\\\\ No newline at end of file ---- -> seven" - dotest_fail diffnl-301 "${testcvs} diff -u abc" \ -"Index: abc -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -retrieving revision 1\.3 -diff -u -r1\.3 abc ---- abc ${RFCDATE} 1\.3 -+++ abc ${RFCDATE} -@@ -2,4 +2,4 @@ - two - three - four --seven -\\\\ No newline at end of file -+seven" - dotest diffnl-302 "${testcvs} ci -mtest abc" \ -"Checking in abc; -${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc -new revision: 1\.4; previous revision: 1\.3 -done" - - # Removal of newline - ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nseven")}' </dev/null >abc - dotest_fail diffnl-400 "${testcvs} diff abc" \ -"Index: abc -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -retrieving revision 1\.4 -diff -r1\.4 abc -5c5 -< seven ---- -> seven -\\\\ No newline at end of file" - dotest_fail diffnl-401 "${testcvs} diff -u abc" \ -"Index: abc -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -retrieving revision 1\.4 -diff -u -r1\.4 abc ---- abc ${RFCDATE} 1\.4 -+++ abc ${RFCDATE} -@@ -2,4 +2,4 @@ - two - three - four --seven -+seven -\\\\ No newline at end of file" - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - death) - # next dive. test death support. - - # NOTE: this section has reached the size and - # complexity where it is getting to be a good idea to - # add new death support tests to a new section rather - # than continuing to piggyback them onto the tests here. - - mkdir ${CVSROOT_DIRNAME}/first-dir - if ${CVS} co first-dir ; then - pass 65 - else - fail 65 - fi - - cd first-dir - - # Create a directory with only dead files, to make sure CVS - # doesn't get confused by it. - mkdir subdir - dotest 65a0 "${testcvs} add subdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository" - cd subdir - echo file in subdir >sfile - dotest 65a1 "${testcvs} add sfile" \ -"${PROG}"' add: scheduling file `sfile'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest 65a2 "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/subdir/sfile,v -done -Checking in sfile; -${CVSROOT_DIRNAME}/first-dir/subdir/sfile,v <-- sfile -initial revision: 1\.1 -done" - rm sfile - dotest 65a3 "${testcvs} rm sfile" \ -"${PROG}"' remove: scheduling `sfile'\'' for removal -'"${PROG}"' remove: use .'"${PROG}"' commit. to remove this file permanently' - dotest 65a4 "${testcvs} -q ci -m remove-it" \ -"Removing sfile; -${CVSROOT_DIRNAME}/first-dir/subdir/sfile,v <-- sfile -new revision: delete; previous revision: 1\.1 -done" - cd .. - dotest 65a5 "${testcvs} -q update -P" '' - dotest_fail 65a6 "test -d subdir" '' - - # add a file. - touch file1 - if ${CVS} add file1 2>> ${LOGFILE}; then - pass 66 - else - fail 66 - fi - - # commit - if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - pass 67 - else - fail 67 - fi - - # remove - rm file1 - if ${CVS} rm file1 2>> ${LOGFILE}; then - pass 68 - else - fail 68 - fi - - # commit - if ${CVS} ci -m test >>${LOGFILE} ; then - pass 69 - else - fail 69 - fi - - dotest_fail 69a0 "test -f file1" '' - # get the old contents of file1 back - if ${testcvs} update -p -r 1.1 file1 >file1 2>>${LOGFILE}; then - pass 69a1 - else - fail 69a1 - fi - dotest 69a2 "cat file1" '' - - # create second file - touch file2 - if ${CVS} add file1 file2 2>> ${LOGFILE}; then - pass 70 - else - fail 70 - fi - - # commit - if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - pass 71 - else - fail 71 - fi - - # log - if ${CVS} log file1 >> ${LOGFILE}; then - pass 72 - else - fail 72 - fi - - # file4 will be dead at the time of branching and stay dead. - echo file4 > file4 - dotest death-file4-add "${testcvs} add file4" \ -"${PROG}"' add: scheduling file `file4'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest death-file4-ciadd "${testcvs} -q ci -m add file4" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -initial revision: 1\.1 -done" - rm file4 - dotest death-file4-rm "${testcvs} remove file4" \ -"${PROG}"' remove: scheduling `file4'\'' for removal -'"${PROG}"' remove: use .'"${PROG}"' commit. to remove this file permanently' - dotest death-file4-cirm "${testcvs} -q ci -m remove file4" \ -"Removing file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: delete; previous revision: 1\.1 -done" - - # Tag the branchpoint. - dotest death-72a "${testcvs} -q tag bp_branch1" 'T file1 -T file2' - - # branch1 - if ${CVS} tag -b branch1 ; then - pass 73 - else - fail 73 - fi - - # and move to the branch. - if ${CVS} update -r branch1 ; then - pass 74 - else - fail 74 - fi - - dotest_fail death-file4-3 "test -f file4" '' - - # add a file in the branch - echo line1 from branch1 >> file3 - if ${CVS} add file3 2>> ${LOGFILE}; then - pass 75 - else - fail 75 - fi - - # commit - if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - pass 76 - else - fail 76 - fi - - dotest death-76a0 \ -"${testcvs} -q rdiff -r bp_branch1 -r branch1 first-dir" \ -"Index: first-dir/file3 -diff -c /dev/null first-dir/file3:1\.1\.2\.1 -\*\*\* /dev/null ${DATE} ---- first-dir/file3 ${DATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 0 \*\*\*\* ---- 1 ---- -${PLUS} line1 from branch1" - dotest death-76a1 \ -"${testcvs} -q rdiff -r branch1 -r bp_branch1 first-dir" \ -"Index: first-dir/file3 -diff -c first-dir/file3:1\.1\.2\.1 first-dir/file3:removed -\*\*\* first-dir/file3:1\.1\.2\.1 ${DATE} ---- first-dir/file3 ${DATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -- line1 from branch1 ---- 0 ----" - - # remove - rm file3 - if ${CVS} rm file3 2>> ${LOGFILE}; then - pass 77 - else - fail 77 - fi - - # commit - if ${CVS} ci -m test >>${LOGFILE} ; then - pass 78 - else - fail 78 - fi - - # add again - echo line1 from branch1 >> file3 - if ${CVS} add file3 2>> ${LOGFILE}; then - pass 79 - else - fail 79 - fi - - # commit - if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - pass 80 - else - fail 80 - fi - - # change the first file - echo line2 from branch1 >> file1 - - # commit - if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - pass 81 - else - fail 81 - fi - - # remove the second - rm file2 - if ${CVS} rm file2 2>> ${LOGFILE}; then - pass 82 - else - fail 82 - fi - - # commit - if ${CVS} ci -m test >>${LOGFILE}; then - pass 83 - else - fail 83 - fi - - # back to the trunk. - if ${CVS} update -A 2>> ${LOGFILE}; then - pass 84 - else - fail 84 - fi - - dotest_fail death-file4-4 "test -f file4" '' - - if test -f file3 ; then - fail 85 - else - pass 85 - fi - - # join - dotest 86 "${testcvs} -q update -j branch1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.3 -retrieving revision 1\.3\.2\.1 -Merging differences between 1\.3 and 1\.3\.2\.1 into file1 -${PROG} update: scheduling file2 for removal -U file3" - - dotest_fail death-file4-5 "test -f file4" '' - - if test -f file3 ; then - pass 87 - else - fail 87 - fi - - # Make sure that we joined the correct change to file1 - if echo line2 from branch1 | cmp - file1 >/dev/null; then - pass 87a - else - fail 87a - fi - - # update - if ${CVS} update ; then - pass 88 - else - fail 88 - fi - - # commit - dotest 89 "${testcvs} -q ci -m test" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.4; previous revision: 1\.3 -done -Removing file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: delete; previous revision: 1\.1 -done -Checking in file3; -${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3 -new revision: 1\.2; previous revision: 1\.1 -done" - cd .. - mkdir 2 - cd 2 - dotest 89a "${testcvs} -q co first-dir" 'U first-dir/file1 -U first-dir/file3' - cd .. - rm -r 2 - cd first-dir - - # remove first file. - rm file1 - if ${CVS} rm file1 2>> ${LOGFILE}; then - pass 90 - else - fail 90 - fi - - # commit - if ${CVS} ci -m test >>${LOGFILE}; then - pass 91 - else - fail 91 - fi - - if test -f file1 ; then - fail 92 - else - pass 92 - fi - - # typo; try to get to the branch and fail - dotest_fail 92.1a "${testcvs} update -r brnach1" \ - "${PROG}"' \[update aborted\]: no such tag brnach1' - # Make sure we are still on the trunk - if test -f file1 ; then - fail 92.1b - else - pass 92.1b - fi - if test -f file3 ; then - pass 92.1c - else - fail 92.1c - fi - - # back to branch1 - if ${CVS} update -r branch1 2>> ${LOGFILE}; then - pass 93 - else - fail 93 - fi - - dotest_fail death-file4-6 "test -f file4" '' - - if test -f file1 ; then - pass 94 - else - fail 94 - fi - - # and join - dotest 95 "$testcvs -q update -j HEAD" \ -"$PROG update: file file1 has been removed in revision HEAD, but the destination is incompatibly modified -C file1 -$PROG update: file file3 exists, but has been added in revision HEAD" - - dotest_fail death-file4-7 "test -f file4" '' - - # file2 should not have been recreated. It was - # deleted on the branch, and has not been modified on - # the trunk. That means that there have been no - # changes between the greatest common ancestor (the - # trunk version) and HEAD. - dotest_fail death-file2-1 "test -f file2" '' - - cd .. ; rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir - ;; - - death2) - # More tests of death support. - mkdir ${CVSROOT_DIRNAME}/first-dir - dotest death2-1 "${testcvs} -q co first-dir" '' - - cd first-dir - - # Add two files on the trunk. - echo "first revision" > file1 - echo "file4 first revision" > file4 - dotest death2-2 "${testcvs} add file1 file4" \ -"${PROG}"' add: scheduling file `file1'\'' for addition -'"${PROG}"' add: scheduling file `file4'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add these files permanently' - - dotest death2-3 "${testcvs} -q commit -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -initial revision: 1\.1 -done" - - # Make a branch and a non-branch tag. - dotest death2-4 "${testcvs} -q tag -b branch" \ -'T file1 -T file4' - dotest death2-5 "${testcvs} -q tag tag" \ -'T file1 -T file4' - - # Switch over to the branch. - dotest death2-6 "$testcvs -q update -r branch" \ -'[UP] file1 -[UP] file4' - - # Delete the file on the branch. - rm file1 - dotest death2-7 "${testcvs} rm file1" \ -"${PROG} remove: scheduling .file1. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - - # Test diff of the removed file before it is committed. - dotest_fail death2-diff-1 "${testcvs} -q diff file1" \ -"${PROG} diff: file1 was removed, no comparison available" - - dotest_fail death2-diff-2 "${testcvs} -q diff -N -c file1" \ -"Index: file1 -=================================================================== -RCS file: file1 -diff -N file1 -\*\*\* file1 ${RFCDATE} [0-9.]* ---- /dev/null ${RFCDATE_EPOCH} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -- first revision ---- 0 ----" - - dotest death2-8 "${testcvs} -q ci -m removed" \ -"Removing file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done" - - # Test diff of a dead file. - dotest_fail death2-diff-3 \ -"${testcvs} -q diff -r1.1 -rbranch -c file1" \ -"${PROG} diff: Tag branch refers to a dead (removed) revision in file .file1.\. -${PROG} diff: No comparison available\. Pass .-N. to .${PROG} diff.${QUESTION}" - # and in reverse - dotest_fail death2-diff-3a \ -"${testcvs} -q diff -rbranch -r1.1 -c file1" \ -"${PROG} diff: Tag branch refers to a dead (removed) revision in file .file1.\. -${PROG} diff: No comparison available\. Pass .-N. to .${PROG} diff.${QUESTION}" - - dotest_fail death2-diff-4 \ -"${testcvs} -q diff -r1.1 -rbranch -N -c file1" \ -"Index: file1 -=================================================================== -RCS file: file1 -diff -N file1 -\*\*\* file1 ${RFCDATE} [0-9.]* ---- /dev/null ${RFCDATE_EPOCH} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -- first revision ---- 0 ----" - # and in reverse - dotest_fail death2-diff-4a \ -"${testcvs} -q diff -rbranch -r1.1 -N -c file1" \ -"Index: file1 -=================================================================== -RCS file: file1 -diff -N file1 -\*\*\* /dev/null ${RFCDATE_EPOCH} ---- file1 ${RFCDATE} [0-9.]* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 0 \*\*\*\* ---- 1 ---- -+ first revision" - - - dotest_fail death2-diff-5 "${testcvs} -q diff -rtag -c ." \ -"${PROG} diff: file1 no longer exists, no comparison available" - - dotest_fail death2-diff-6 "${testcvs} -q diff -rtag -N -c ." \ -"Index: file1 -=================================================================== -RCS file: file1 -diff -N file1 -\*\*\* file1 [-a-zA-Z0-9: ]* [0-9.]* ---- /dev/null ${RFCDATE_EPOCH} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -- first revision ---- 0 ----" - - # Test rdiff of a dead file. - dotest death2-rdiff-1 \ -"${testcvs} -q rtag -rbranch rdiff-tag first-dir" '' - - dotest death2-rdiff-2 "${testcvs} -q rdiff -rtag -rbranch first-dir" \ -"Index: first-dir/file1 -diff -c first-dir/file1:1\.1 first-dir/file1:removed -\*\*\* first-dir/file1:1\.1 [a-zA-Z0-9: ]* ---- first-dir/file1 [a-zA-Z0-9: ]* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -- first revision ---- 0 ----" - - # Readd the file to the branch. - echo "second revision" > file1 - dotest death2-9 "${testcvs} add file1" \ -"${PROG}"' add: file `file1'\'' will be added on branch `branch'\'' from version 1\.1\.2\.1 -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - - # Test diff of the added file before it is committed. - dotest_fail death2-diff-7 "${testcvs} -q diff file1" \ -"${PROG} diff: file1 is a new entry, no comparison available" - - dotest_fail death2-diff-8 "${testcvs} -q diff -N -c file1" \ -"Index: file1 -=================================================================== -RCS file: file1 -diff -N file1 -\*\*\* /dev/null ${RFCDATE_EPOCH} ---- file1 ${RFCDATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 0 \*\*\*\* ---- 1 ---- -${PLUS} second revision" - - dotest death2-10 "${testcvs} -q commit -m add" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 -done" - - # Delete file4 from the branch - dotest death2-10a "${testcvs} rm -f file4" \ -"${PROG} remove: scheduling .file4. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest death2-10b "${testcvs} -q ci -m removed" \ -"Removing file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: delete; previous revision: 1\.1 -done" - - # Back to the trunk. - dotest death2-11 "${testcvs} -q update -A" \ -"[UP] file1 -U file4" - - # Add another file on the trunk. - echo "first revision" > file2 - dotest death2-12 "${testcvs} add file2" \ -"${PROG}"' add: scheduling file `file2'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest death2-13 "${testcvs} -q commit -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - - # Modify file4 on the trunk. - echo "new file4 revision" > file4 - dotest death2-13a "${testcvs} -q commit -m mod" \ -"Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: 1\.2; previous revision: 1\.1 -done" - - # Back to the branch. - # The ``no longer in the repository'' message doesn't really - # look right to me, but that's what CVS currently prints for - # this case. - dotest death2-14 "${testcvs} -q update -r branch" \ -"[UP] file1 -${PROG} update: file2 is no longer in the repository -${PROG} update: file4 is no longer in the repository" - - # Add a file on the branch with the same name. - echo "branch revision" > file2 - dotest death2-15 "${testcvs} add file2" \ -"${PROG}"' add: scheduling file `file2'\'' for addition on branch `branch'\'' -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest death2-16 "${testcvs} -q commit -m add" \ -"Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 -done" - - # Add a new file on the branch. - echo "first revision" > file3 - dotest death2-17 "${testcvs} add file3" \ -"${PROG}"' add: scheduling file `file3'\'' for addition on branch `branch'\'' -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest death2-18 "${testcvs} -q commit -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v -done -Checking in file3; -${CVSROOT_DIRNAME}/first-dir/Attic/file3,v <-- file3 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - # Test diff of a nonexistent tag - dotest_fail death2-diff-9 "${testcvs} -q diff -rtag -c file3" \ -"${PROG} diff: tag tag is not in file file3" - - dotest_fail death2-diff-10 "${testcvs} -q diff -rtag -N -c file3" \ -"Index: file3 -=================================================================== -RCS file: file3 -diff -N file3 -\*\*\* /dev/null ${RFCDATE_EPOCH} ---- file3 ${RFCDATE} [0-9.]* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 0 \*\*\*\* ---- 1 ---- -${PLUS} first revision" - - dotest_fail death2-diff-11 "${testcvs} -q diff -rtag -c ." \ -"Index: file1 -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.1 -retrieving revision 1\.1\.2\.2 -diff -c -r1\.1 -r1\.1\.2\.2 -\*\*\* file1 ${RFCDATE} [0-9.]* ---- file1 ${RFCDATE} [0-9.]* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -! first revision ---- 1 ---- -! second revision -${PROG} diff: tag tag is not in file file2 -${PROG} diff: tag tag is not in file file3 -${PROG} diff: file4 no longer exists, no comparison available" - - dotest_fail death2-diff-12 "${testcvs} -q diff -rtag -c -N ." \ -"Index: file1 -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.1 -retrieving revision 1\.1\.2\.2 -diff -c -r1\.1 -r1\.1\.2\.2 -\*\*\* file1 ${RFCDATE} [0-9.]* ---- file1 ${RFCDATE} [0-9.]* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -! first revision ---- 1 ---- -! second revision -Index: file2 -=================================================================== -RCS file: file2 -diff -N file2 -\*\*\* /dev/null ${RFCDATE_EPOCH} ---- file2 ${RFCDATE} [0-9.]* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 0 \*\*\*\* ---- 1 ---- -${PLUS} branch revision -Index: file3 -=================================================================== -RCS file: file3 -diff -N file3 -\*\*\* /dev/null ${RFCDATE_EPOCH} ---- file3 ${RFCDATE} [0-9.]* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 0 \*\*\*\* ---- 1 ---- -${PLUS} first revision -Index: file4 -=================================================================== -RCS file: file4 -diff -N file4 -\*\*\* file4 ${RFCDATE} [0-9.]* ---- /dev/null ${RFCDATE_EPOCH} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -- file4 first revision ---- 0 ----" - - # Switch to the nonbranch tag. - dotest death2-19 "${testcvs} -q update -r tag" \ -"[UP] file1 -${PROG} update: file2 is no longer in the repository -${PROG} update: file3 is no longer in the repository -U file4" - - dotest_fail death2-20 "test -f file2" - - # Make sure diff only reports appropriate files. - dotest_fail death2-diff-13 "${testcvs} -q diff -r rdiff-tag" \ -"${PROG} diff: Tag rdiff-tag refers to a dead (removed) revision in file .file1.\. -${PROG} diff: No comparison available\. Pass .-N. to .${PROG} diff.${QUESTION}" - - dotest_fail death2-diff-14 "${testcvs} -q diff -r rdiff-tag -c -N" \ -"Index: file1 -=================================================================== -RCS file: file1 -diff -N file1 -\*\*\* /dev/null ${RFCDATE_EPOCH} ---- file1 ${RFCDATE} [0-9.]* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 0 \*\*\*\* ---- 1 ---- -${PLUS} first revision" - - # now back to the trunk - dotest death2-21 "$testcvs -q update -A" \ -'[UP] file1 -U file2 -U file4' - - # test merging with a dead file - dotest death2-22 "${testcvs} -q co first-dir" \ -"U first-dir/file1 -U first-dir/file2 -U first-dir/file4" - - cd first-dir - dotest death2-23 "${testcvs} rm -f file4" \ -"${PROG} remove: scheduling .file4. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest death2-24 "${testcvs} -q ci -m removed file4" \ -"Removing file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: delete; previous revision: 1\.2 -done" - cd .. - echo "new stuff" >file4 - dotest_fail death2-25 "${testcvs} up file4" \ -"${PROG} update: conflict: file4 is modified but no longer in the repository -C file4" - - cd .. ; rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir - ;; - - - - death-rtag) - # This documents a bug in CVS that prevents rtag from tagging files - # in the Attic. - mkdir $CVSROOT_DIRNAME/death-rtag - dotest death-rtag-init-1 "$testcvs -Q co death-rtag" - cd death-rtag - echo "This is the file foo" > foo - echo "This is the file bar" > bar - dotest death-rtag-init-2 "$testcvs -Q add foo bar" - dotest death-rtag-init-3 "$testcvs -Q ci -m 'Add foo and bar.'" \ -"RCS file: $CVSROOT_DIRNAME/death-rtag/bar,v -done -Checking in bar; -$CVSROOT_DIRNAME/death-rtag/bar,v <-- bar -initial revision: 1\.[0-9]* -done -RCS file: $CVSROOT_DIRNAME/death-rtag/foo,v -done -Checking in foo; -$CVSROOT_DIRNAME/death-rtag/foo,v <-- foo -initial revision: 1\.[0-9]* -done" - dotest death-rtag-init-5 "$testcvs -Q tag -b mybranch" - - dotest death-rtag-1 "$testcvs -q rtag -rmybranch willtag death-rtag" - dotest death-rtag-2 "$testcvs -Q rm -f foo" - dotest death-rtag-3 "$testcvs -Q ci -m 'Remove foo.'" \ -"Removing foo; -$CVSROOT_DIRNAME/death-rtag/foo,v <-- foo -new revision: delete; previous revision: 1\.[0-9]* -done" - # commit something on the branch so that the moving tag is visible. - dotest death-rtag-3.2 "$testcvs -Q up -rmybranch" - echo some branch content >>foo - echo some branch content >>bar - dotest death-rtag-3.3 "$testcvs -Q ci -m 'Change foo.'" \ -"Checking in bar; -$CVSROOT_DIRNAME/death-rtag/bar,v <-- bar -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in foo; -$CVSROOT_DIRNAME/death-rtag/Attic/foo,v <-- foo -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - dotest death-rtag-3.4 \ -"$testcvs -q rtag -rmybranch wontmove death-rtag" - dotest death-rtag-3.5 "$testcvs -q rtag -F wontmove death-rtag" - - cd .. - # Removing -f below avoids this bug. - dotest death-rtag-4 "$testcvs -q rtag -frmybranch wonttag death-rtag" - - # When the bug existed, `wonttag' would not have been present in - # foo,v. - # - # A second bug prevented `wontmove' from moving from the branch to - # the dead revision on the trunk (death-rtag-3.4 & death-rtag-3.5). - dotest death-rtag-5 "$testcvs -q rlog death-rtag" \ -" -RCS file: $CVSROOT_DIRNAME/death-rtag/bar,v -head: 1.[0-9]* -branch: -locks: strict -access list: -symbolic names: - wonttag: 1\.1\.2\.1 - wontmove: 1\.1 - willtag: 1\.1 - mybranch: 1\.1.0\.2 -keyword substitution: kv -$DOTSTAR -RCS file: $CVSROOT_DIRNAME/death-rtag/Attic/foo,v -head: 1.[0-9]* -branch: -locks: strict -access list: -symbolic names: - wonttag: 1\.1\.2\.1 - wontmove: 1\.2 - willtag: 1\.1 - mybranch: 1\.1.0\.2 -keyword substitution: kv -$DOTSTAR" - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - rm -r death-rtag - rm -rf $CVSROOT_DIRNAME/death-rtag - ;; - - - - rm-update-message) - # FIXME - # local CVS prints a warning message when update notices a missing - # file and client/server CVS doesn't. These should be identical. - mkdir rm-update-message; cd rm-update-message - mkdir $CVSROOT_DIRNAME/rm-update-message - dotest rm-update-message-setup-1 "$testcvs -q co rm-update-message" '' - cd rm-update-message - file=x - echo >$file - dotest rm-update-message-setup-2 "$testcvs -q add $file" \ -"${PROG} add: use .${PROG} commit. to add this file permanently" - dotest rm-update-message-setup-3 "$testcvs -q ci -mcreate $file" \ -"RCS file: $CVSROOT_DIRNAME/rm-update-message/$file,v -done -Checking in $file; -$CVSROOT_DIRNAME/rm-update-message/$file,v <-- $file -initial revision: 1\.1 -done" - - rm $file - dotest rm-update-message-1 "$testcvs up $file" \ -"${PROG} update: warning: $file was lost -U $file" - - cd ../.. - if $keep; then :; else - rm -rf rm-update-message - rm -rf $CVSROOT_DIRNAME/rm-update-message - fi - ;; - - rmadd) - # More tests of adding and removing files. - # In particular ci -r. - # Other ci -r tests: - # * editor-9: checking in a modified file, - # where "ci -r" means a branch. - # * basica-8a1: checking in a modified file with numeric revision. - # * basica-8a2: likewise. - # * keywordlog-4: adding a new file with numeric revision. - mkdir 1; cd 1 - dotest rmadd-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest rmadd-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - echo first file1 >file1 - dotest rmadd-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - - dotest_fail rmadd-4 "${testcvs} -q ci -r 1.2.2.4 -m add" \ -"${PROG} commit: cannot add file .file1' with revision .1\.2\.2\.4'; must be on trunk -${PROG} \[commit aborted\]: correct above errors first!" - dotest_fail rmadd-5 "${testcvs} -q ci -r 1.2.2 -m add" \ -"${PROG} commit: cannot add file .file1' with revision .1\.2\.2'; must be on trunk -${PROG} \[commit aborted\]: correct above errors first!" - dotest_fail rmadd-6 "${testcvs} -q ci -r mybranch -m add" \ -"${PROG} \[commit aborted\]: no such tag mybranch" - - # The thing with the trailing periods strikes me as a very - # bizarre behavior, but it would seem to be intentional - # (see commit.c). It probably could go away.... - dotest rmadd-7 "${testcvs} -q ci -r 7.... -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 7\.1 -done" - if $remote; then - # I guess remote doesn't set a sticky tag in this case. - # Kind of odd, in the sense that rmadd-24a does set one - # both local and remote. - dotest_fail rmadd-7a "test -f CVS/Tag" - echo T7 >CVS/Tag - else - dotest rmadd-7a "cat CVS/Tag" "T7" - fi - - dotest rmadd-8 "${testcvs} -q tag -b mybranch" "T file1" - dotest rmadd-9 "${testcvs} -q tag mynonbranch" "T file1" - - touch file2 - # The previous "cvs ci -r" set a sticky tag of '7'. Seems a - # bit odd, and I guess commit.c (findmaxrev) makes '7' sticky - # tags unnecessary (?). I kind of suspect that it should be - # saying "sticky tag is not a branch" like keywordlog-4b. - # Or something. - dotest rmadd-10 "${testcvs} add file2" \ -"${PROG} add: scheduling file .file2. for addition on branch .7' -${PROG} add: use .${PROG} commit. to add this file permanently" - # As in the previous example, CVS is confused.... - dotest rmadd-11 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 7\.1 -done" - - dotest rmadd-12 "${testcvs} -q update -A" "" - touch file3 - dotest rmadd-13 "${testcvs} add file3" \ -"${PROG} add: scheduling file .file3. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - # Huh? file2 is not up to date? Seems buggy to me.... - dotest_fail rmadd-14 "${testcvs} -q ci -r mybranch -m add" \ -"${PROG} commit: Up-to-date check failed for .file2' -${PROG} \[commit aborted\]: correct above errors first!" - # Whatever, let's not let file2 distract us.... - dotest rmadd-15 "${testcvs} -q ci -r mybranch -m add file3" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v -done -Checking in file3; -${CVSROOT_DIRNAME}/first-dir/Attic/file3,v <-- file3 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - touch file4 - dotest rmadd-16 "${testcvs} add file4" \ -"${PROG} add: scheduling file .file4. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - # Same "Up-to-date check" issues as in rmadd-14. - # The "no such tag" thing is due to the fact that we only - # update val-tags when the tag is used (might be more of a - # bug than a feature, I dunno). - dotest_fail rmadd-17 \ -"${testcvs} -q ci -r mynonbranch -m add file4" \ -"${PROG} \[commit aborted\]: no such tag mynonbranch" - # Try to make CVS write val-tags. - dotest rmadd-18 "${testcvs} -q update -p -r mynonbranch file1" \ -"first file1" - # Oops, -p suppresses writing val-tags (probably a questionable - # behavior). - dotest_fail rmadd-19 \ -"${testcvs} -q ci -r mynonbranch -m add file4" \ -"${PROG} \[commit aborted\]: no such tag mynonbranch" - # Now make CVS write val-tags for real. - dotest rmadd-20 "$testcvs -q update -r mynonbranch file1" '[UP] file1' - # Oops - CVS isn't distinguishing between a branch tag and - # a non-branch tag. - dotest rmadd-21 \ -"${testcvs} -q ci -r mynonbranch -m add file4" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file4,v -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/Attic/file4,v <-- file4 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - # OK, we add this one in a vanilla way, but then check in - # a modification with ci -r and sniff around for sticky tags. - echo file5 >file5 - dotest rmadd-22 "${testcvs} add file5" \ -"${PROG} add: scheduling file .file5. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - if $remote; then - # Interesting bug (or missing feature) here. findmaxrev - # gets the major revision from the Entries. Well, remote - # doesn't send the entries for files which are not involved. - dotest rmadd-23r "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file5,v -done -Checking in file5; -${CVSROOT_DIRNAME}/first-dir/file5,v <-- file5 -initial revision: 1\.1 -done" - dotest rmadd-23-workaroundr \ -"${testcvs} -q ci -r 7 -m bump-it file5" \ -"Checking in file5; -${CVSROOT_DIRNAME}/first-dir/file5,v <-- file5 -new revision: 7\.1; previous revision: 1\.1 -done" - else - dotest rmadd-23 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file5,v -done -Checking in file5; -${CVSROOT_DIRNAME}/first-dir/file5,v <-- file5 -initial revision: 7\.1 -done" - fi - echo change it >file5 - dotest_fail rmadd-24 "${testcvs} -q ci -r 4.8 -m change file5" \ -"Checking in file5; -${CVSROOT_DIRNAME}/first-dir/file5,v <-- file5 -${PROG} commit: ${CVSROOT_DIRNAME}/first-dir/file5,v: revision 4\.8 too low; must be higher than 7\.1 -${PROG} commit: could not check in file5" - dotest rmadd-24a "${testcvs} -q ci -r 8.4 -m change file5" \ -"Checking in file5; -${CVSROOT_DIRNAME}/first-dir/file5,v <-- file5 -new revision: 8\.4; previous revision: 7\.1 -done" - # I'm not really sure that a sticky tag make sense here. - # It seems to be longstanding behavior for what that is worth. - dotest rmadd-25 "${testcvs} status file5" \ -"=================================================================== -File: file5 Status: Up-to-date - - Working revision: 8\.4.* - Repository revision: 8\.4 ${CVSROOT_DIRNAME}/first-dir/file5,v - Sticky Tag: 8\.4 - Sticky Date: (none) - Sticky Options: (none)" - - # now try forced revision with recursion - mkdir sub - dotest rmadd-26 "${testcvs} -q add sub" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/sub added to the repository" - echo hello >sub/subfile - dotest rmadd-27 "${testcvs} -q add sub/subfile" \ -"${PROG} add: use .${PROG} commit. to add this file permanently" - - dotest rmadd-28 "${testcvs} -q ci -m. sub" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sub/subfile,v -done -Checking in sub/subfile; -${CVSROOT_DIRNAME}/first-dir/sub/subfile,v <-- subfile -initial revision: 1\.1 -done" - - # lose the branch - dotest rmadd-29 "$testcvs -q up -A" \ -"[UP] file1 -$PROG update: file3 is no longer in the repository -$PROG update: file4 is no longer in the repository" - - # -f disables recursion - dotest rmadd-30 "${testcvs} -q ci -f -r9 -m." \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 9\.1; previous revision: 7\.1 -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 9\.1; previous revision: 7\.1 -done -Checking in file5; -${CVSROOT_DIRNAME}/first-dir/file5,v <-- file5 -new revision: 9\.1; previous revision: 8\.4 -done" - - # add -R to force recursion - dotest rmadd-31 "${testcvs} -q ci -f -r9 -R -m." \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 9\.2; previous revision: 9\.1 -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 9\.2; previous revision: 9\.1 -done -Checking in file5; -${CVSROOT_DIRNAME}/first-dir/file5,v <-- file5 -new revision: 9\.2; previous revision: 9\.1 -done -Checking in sub/subfile; -${CVSROOT_DIRNAME}/first-dir/sub/subfile,v <-- subfile -new revision: 9\.1; previous revision: 1\.1 -done" - - if $remote; then - # as noted above, remote doesn't set a sticky tag - : - else - dotest rmadd-32 "cat CVS/Tag" "T9" - dotest rmadd-33 "cat sub/CVS/Tag" "T9" - fi - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - rmadd2) - # Tests of undoing commits, including in the presence of - # adding and removing files. See join for a list of -j tests. - mkdir 1; cd 1 - dotest rmadd2-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest rmadd2-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - echo 'initial contents' >file1 - dotest rmadd2-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest rmadd2-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - dotest rmadd2-4a "${testcvs} -Q tag tagone" "" - dotest rmadd2-5 "${testcvs} rm -f file1" \ -"${PROG} remove: scheduling .file1. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest rmadd2-6 "${testcvs} -q ci -m remove" \ -"Removing file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done" - dotest rmadd2-7 "${testcvs} -q update -j 1.2 -j 1.1 file1" "U file1" - dotest rmadd2-8 "${testcvs} -q ci -m readd" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 -done" - echo 'new contents' >file1 - dotest rmadd2-9 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.4; previous revision: 1\.3 -done" - dotest rmadd2-10 "${testcvs} -q update -j 1.4 -j 1.3 file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.4 -retrieving revision 1\.3 -Merging differences between 1\.4 and 1\.3 into file1" - dotest rmadd2-11 "${testcvs} -q ci -m undo" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.5; previous revision: 1\.4 -done" - dotest rmadd2-12 "cat file1" "initial contents" - dotest rmadd2-13 "${testcvs} -q update -p -r 1.3" "initial contents" - - # Hmm, might be a bit odd that this works even if 1.3 is not - # the head. - dotest rmadd2-14 "${testcvs} -q update -j 1.3 -j 1.2 file1" \ -"${PROG} update: scheduling file1 for removal" - - # Check that -p can get arbitrary revisions of a removed file - dotest rmadd2-14a "${testcvs} -q update -p" "initial contents" - dotest rmadd2-14b "${testcvs} -q update -p -r 1.5" "initial contents" - dotest rmadd2-14c "${testcvs} -q update -p -r 1.3" "initial contents" - - dotest rmadd2-15 "${testcvs} -q ci -m re-remove" \ -"Removing file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: delete; previous revision: 1\.5 -done" - dotest rmadd2-16 "${testcvs} log -h file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -Working file: file1 -head: 1\.6 -branch: -locks: strict -access list: -symbolic names: - tagone: 1\.1 -keyword substitution: kv -total revisions: 6 -=============================================================================" - dotest rmadd2-17 "${testcvs} status -v file1" \ -"=================================================================== -File: no file file1 Status: Up-to-date - - Working revision: No entry for file1 - Repository revision: 1\.6 ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v - - Existing Tags: - tagone (revision: 1.1)" - - cd ../.. - - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - rmadd3) - # This test demonstrates that CVS notices that file1 exists rather - # that deleting or writing over it after: - # - # cvs remove -f file1; touch file1; cvs add file1. - # - # According to the manual, this should work for: - # - # rm file1; cvs remove file1; cvs add file1 - # - # but in past version of CVS, new content in file1 would be - # erroneously deleted when file1 reappeared between the remove and - # the add. - # - # Later versions of CVS would refuse to perform the add, but still - # allow a subsequent local commit to erase the file from the - # workspace, possibly losing data. - mkdir 1; cd 1 - dotest rmadd3-init1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest rmadd3-init2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - echo initial content for file1 >file1 - dotest rmadd3-init3 "${testcvs} add file1" \ -"${PROG} add: scheduling file \`file1' for addition -${PROG} add: use '${PROG} commit' to add this file permanently" - dotest rmadd3-init4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - - # Here begins the guts of this test, as detailed above. - dotest rmadd3-1 "${testcvs} rm -f file1" \ -"${PROG} remove: scheduling \`file1' for removal -${PROG} remove: use '${PROG} commit' to remove this file permanently" - - # Now recreate the file: - echo desired future contents for file1 >file1 - - # And attempt to resurrect it at the same time: - dotest_fail rmadd3-2 "${testcvs} add file1" \ -"${PROG} add: file1 should be removed and is still there (or is back again)" - - # Now prove that commit knows that it shouldn't erase files. - dotest_fail rmadd3-3 "${testcvs} -q ci -m." \ -"$PROG commit: \`file1' should be removed and is still there (or is back again) -$PROG \[commit aborted\]: correct above errors first!" - - # Then these should pass too: - dotest rmadd3-4 "test -f file1" - dotest rmadd3-5 "cat file1" "desired future contents for file1" - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - resurrection) - # This test tests a few file resurrection scenarios. - mkdir 1; cd 1 - dotest resurrection-init1 "$testcvs -q co -l ." '' - mkdir first-dir - dotest resurrection-init2 "$testcvs add first-dir" \ -"Directory $CVSROOT_DIRNAME/first-dir added to the repository" - cd first-dir - - echo initial content for file1 >file1 - dotest resurrection-init3 "$testcvs add file1" \ -"$PROG add: scheduling file \`file1' for addition -$PROG add: use '$PROG commit' to add this file permanently" - dotest resurrection-init4 "$testcvs -q ci -m add" \ -"RCS file: $CVSROOT_DIRNAME/first-dir/file1,v -done -Checking in file1; -$CVSROOT_DIRNAME/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - - dotest resurrection-init5 "$testcvs -Q rm -f file1" - - # The first test is that `cvs add' will resurrect a file before its - # removal has been committed. - dotest_sort resurrection-1 "$testcvs add file1" \ -"U file1 -$PROG add: file1, version 1\.1, resurrected" - dotest resurrection-2 "$testcvs -Q diff file1" "" - - dotest resurrection-init6 "$testcvs -Q tag -b resurrection" - dotest resurrection-init7 "$testcvs -Q rm -f file1" - dotest resurrection-init8 "$testcvs -Q ci -mrm" \ -"Removing file1; -$CVSROOT_DIRNAME/first-dir/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done" - - # The next test is that CVS will resurrect a committed removal. - dotest_sort resurrection-3 "$testcvs add file1" \ -"U file1 -$PROG add: Re-adding file \`file1' (in place of dead revision 1\.2)\. -$PROG add: Resurrecting file \`file1' from revision 1\.1\. -$PROG add: use 'cvs commit' to add this file permanently" - dotest resurrection-4 "$testcvs -q diff -r1.1 file1" "" - dotest resurrection-5 "$testcvs -q ci -mreadd" \ -"Checking in file1; -$CVSROOT_DIRNAME/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 -done" - - dotest resurrection-init9 "$testcvs -Q up -rresurrection" - dotest resurrection-init10 "$testcvs -Q rm -f file1" - dotest resurrection-init11 "$testcvs -Q ci -mrm-on-resurrection" \ -"Removing file1; -$CVSROOT_DIRNAME/first-dir/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done" - - # The next test is that CVS will resurrect a committed removal to a - # branch. - dotest_sort resurrection-6 "$testcvs add file1" \ -"U file1 -$PROG add: Resurrecting file \`file1' from revision 1\.1\. -$PROG add: file \`file1' will be added on branch \`resurrection' from version 1\.1\.2\.1 -$PROG add: use 'cvs commit' to add this file permanently" - dotest resurrection-7 "$testcvs -Q diff -r1.1 file1" "" - dotest resurrection-8 "$testcvs -q ci -mreadd" \ -"Checking in file1; -$CVSROOT_DIRNAME/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 -done" - - # The next few tests verify that an attempted resurrection of a file - # with no previous revision on the trunk fails. - touch file2 - dotest resurrection-9 "$testcvs -Q add file2" - dotest resurrection-10 "$testcvs -Q ci -mnew-file2" \ -"RCS file: $CVSROOT_DIRNAME/first-dir/Attic/file2,v -done -Checking in file2; -$CVSROOT_DIRNAME/first-dir/Attic/file2,v <-- file2 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - dotest resurrection-11 "$testcvs -Q up -A" - - # This command once caused an assertion failure. - dotest resurrection-12 "$testcvs add file2" \ -"$PROG add: File \`file2' has no previous revision to resurrect\." - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd ../.. - rm -r 1 - rm -rf $CVSROOT_DIRNAME/first-dir - ;; - - dirs) - # Tests related to removing and adding directories. - # See also: - # conflicts (especially dir1 in conflicts-130): What happens if - # directory exists in repository and a non-CVS-controlled - # directory in the working directory? - # conflicts3-15. More cases, especially where CVS directory - # exists but without CVS/Repository and friends. - # conflicts3-22. Similar to conflicts-130 but there is a file - # in the directory. - # dirs2. Sort of similar to conflicts3-22 but somewhat different. - mkdir imp-dir; cd imp-dir - echo file1 >file1 - mkdir sdir - echo sfile >sdir/sfile - dotest_sort dirs-1 \ -"${testcvs} import -m import-it dir1 vend rel" " - -N dir1/file1 -N dir1/sdir/sfile -No conflicts created by this import -${PROG} import: Importing ${CVSROOT_DIRNAME}/dir1/sdir" - cd .. - - mkdir 1; cd 1 - dotest dirs-2 "${testcvs} -Q co dir1" "" - - # Various CVS administrators are in the habit of removing - # the repository directory for things they don't want any - # more. I've even been known to do it myself (on rare - # occasions). Not the usual recommended practice, but we want - # to try to come up with some kind of reasonable/documented/sensible - # behavior. - rm -rf ${CVSROOT_DIRNAME}/dir1/sdir - - dotest dirs-3 "${testcvs} update" \ -"${PROG} update: Updating dir1 -${PROG} update: Updating dir1/sdir -${PROG} update: cannot open directory ${CVSROOT_DIRNAME}/dir1/sdir: No such file or directory -${PROG} update: skipping directory dir1/sdir" - dotest dirs-3a "${testcvs} update -d" \ -"${PROG} update*: Updating dir1 -${PROG} update: Updating dir1/sdir -${PROG} update: cannot open directory ${CVSROOT_DIRNAME}/dir1/sdir: No such file or directory -${PROG} update: skipping directory dir1/sdir" - - # If we say "yes", then CVS gives errors about not being able to - # create lock files. - # The fact that it says "skipping directory " rather than - # "skipping directory dir1/sdir" is some kind of bug. - dotest dirs-4 "echo no | ${testcvs} release -d dir1/sdir" \ -"${PROG} update: cannot open directory ${CVSROOT_DIRNAME}/dir1/sdir: No such file or directory -${PROG} update: skipping directory -You have \[0\] altered files in this repository\. -Are you sure you want to release (and delete) directory .dir1/sdir': .. .release' aborted by user choice." - - # OK, if "cvs release" won't help, we'll try it the other way... - rm -r dir1/sdir - - dotest dirs-5 "cat dir1/CVS/Entries" \ -"/file1/1.1.1.1/[a-zA-Z0-9 :]*// -D/sdir////" - dotest dirs-6 "${testcvs} update" "${PROG} update: Updating dir1" - dotest dirs-7 "cat dir1/CVS/Entries" \ -"/file1/1.1.1.1/[a-zA-Z0-9 :]*// -D/sdir////" - dotest dirs-8 "${testcvs} update -d dir1" \ -"${PROG} update: Updating dir1" - - cd .. - - rm -r imp-dir 1 - - # clean up our repositories - rm -rf ${CVSROOT_DIRNAME}/dir1 - ;; - - dirs2) - # See "dirs" for a list of tests involving adding and - # removing directories. - mkdir 1; cd 1 - dotest dirs2-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest dirs2-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - mkdir sdir - dotest dirs2-3 "${testcvs} add sdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/sdir added to the repository" - touch sdir/file1 - dotest dirs2-4 "${testcvs} add sdir/file1" \ -"${PROG} add: scheduling file .sdir/file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest dirs2-5 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/file1,v -done -Checking in sdir/file1; -${CVSROOT_DIRNAME}/first-dir/sdir/file1,v <-- file1 -initial revision: 1\.1 -done" - rm -r sdir/CVS - if $remote; then - # This is just like conflicts3-23 - dotest_fail dirs2-6 "${testcvs} update -d" \ -"${QUESTION} sdir -${PROG} update: Updating \. -${PROG} update: Updating sdir -${PROG} update: move away sdir/file1; it is in the way -C sdir/file1" - rm sdir/file1 - rm -r sdir/CVS - - # This is where things are not just like conflicts3-23 - dotest dirs2-7 "${testcvs} update -d" \ -"${QUESTION} sdir -${PROG} update: Updating \. -${PROG} update: Updating sdir -U sdir/file1" - else - dotest dirs2-6 "${testcvs} update -d" \ -"${PROG} update: Updating \. -${QUESTION} sdir" - rm sdir/file1 - dotest dirs2-7 "${testcvs} update -d" \ -"${PROG} update: Updating \. -${QUESTION} sdir" - fi - cd ../.. - - # Now, the same thing (more or less) on a branch. - mkdir 2; cd 2 - dotest dirs2-8 "${testcvs} -q co first-dir" 'U first-dir/sdir/file1' - cd first-dir - dotest dirs2-9 "${testcvs} -q tag -b br" "T sdir/file1" - rm -r sdir/CVS - if $remote; then - # Cute little quirk of val-tags; if we don't recurse into - # the directories where the tag is defined, val-tags won't - # get updated. - dotest_fail dirs2-10 "${testcvs} update -d -r br" \ -"${QUESTION} sdir -${PROG} \[update aborted\]: no such tag br" - dotest dirs2-10ar \ -"${testcvs} -q rdiff -u -r 1.1 -r br first-dir/sdir/file1" - dotest_fail dirs2-10-again "${testcvs} update -d -r br" \ -"${QUESTION} sdir -${PROG} update: Updating \. -${PROG} update: Updating sdir -${PROG} update: move away sdir/file1; it is in the way -C sdir/file1" - else - dotest_fail dirs2-10 "${testcvs} update -d -r br" \ -"${PROG} update: in directory sdir: -${PROG} \[update aborted\]: there is no version here; do '${PROG} checkout' first" - fi - cd ../.. - - # OK, the above tests make the situation somewhat harder - # than it might be, in the sense that they actually have a - # file which is alive on the branch we are updating. Let's - # try it where it is just a directory where all the files - # have been removed. - mkdir 3; cd 3 - dotest dirs2-11 "${testcvs} -q co -r br first-dir" \ -"U first-dir/sdir/file1" - cd first-dir - # Hmm, this doesn't mention the branch like add does. That's - # an odd non-orthogonality. - dotest dirs2-12 "${testcvs} rm -f sdir/file1" \ -"${PROG} remove: scheduling .sdir/file1. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest dirs2-13 "${testcvs} -q ci -m remove" \ -"Removing sdir/file1; -${CVSROOT_DIRNAME}/first-dir/sdir/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done" - cd ../../2/first-dir - if $remote; then - dotest dirs2-14 "${testcvs} update -d -r br" \ -"${QUESTION} sdir/file1 -${PROG} update: Updating \. -${PROG} update: Updating sdir" - else - dotest dirs2-14 "${testcvs} update -d -r br" \ -"${PROG} update: Updating \. -${QUESTION} sdir" - fi - cd ../.. - - rm -r 1 2 3 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - branches) - # More branch tests, including branches off of branches - mkdir ${CVSROOT_DIRNAME}/first-dir - dotest branches-1 "${testcvs} -q co first-dir" '' - cd first-dir - echo 1:ancest >file1 - echo 2:ancest >file2 - echo 3:ancest >file3 - echo 4:trunk-1 >file4 - dotest branches-2 "${testcvs} add file1 file2 file3 file4" \ -"${PROG}"' add: scheduling file `file1'\'' for addition -'"${PROG}"' add: scheduling file `file2'\'' for addition -'"${PROG}"' add: scheduling file `file3'\'' for addition -'"${PROG}"' add: scheduling file `file4'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add these files permanently' - dotest branches-2a "${testcvs} -n -q ci -m dont-commit" "" - dotest_lit branches-3 "${testcvs} -q ci -m add-it" <<HERE -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file3,v -done -Checking in file3; -${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -initial revision: 1.1 -done -HERE - echo 4:trunk-2 >file4 - dotest branches-3.2 "${testcvs} -q ci -m trunk-before-branch" \ -"Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: 1\.2; previous revision: 1\.1 -done" - # The "cvs log file4" in test branches-14.3 will test that we - # didn't really add the tag. - dotest branches-3.3 "${testcvs} -qn tag dont-tag" \ -"T file1 -T file2 -T file3 -T file4" - # Modify this file before branching, to deal with the case where - # someone is hacking along, says "oops, I should be doing this on - # a branch", and only then creates the branch. - echo 1:br1 >file1 - dotest branches-4 "${testcvs} tag -b br1" "${PROG}"' tag: Tagging \. -T file1 -T file2 -T file3 -T file4' - dotest branches-5 "$testcvs update -r br1" \ -"$PROG update: Updating \. -M file1 -[UP] file2 -[UP] file3 -[UP] file4" - echo 2:br1 >file2 - echo 4:br1 >file4 - dotest branches-6 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: 1\.2\.2\.1; previous revision: 1\.2 -done" - dotest branches-7 "${testcvs} -q tag -b brbr" 'T file1 -T file2 -T file3 -T file4' - dotest branches-8 "$testcvs -q update -r brbr" \ -'[UP] file1 -[UP] file2 -[UP] file3 -[UP] file4' - echo 1:brbr >file1 - echo 4:brbr >file4 - dotest branches-9 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1\.2\.1; previous revision: 1\.1\.2\.1 -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: 1\.2\.2\.1\.2\.1; previous revision: 1\.2\.2\.1 -done" - dotest branches-10 "cat file1 file2 file3 file4" '1:brbr -2:br1 -3:ancest -4:brbr' - dotest branches-11 "$testcvs -q update -r br1" \ -'U file1 -[UP] file2 -[UP] file3 -U file4' - dotest branches-12 "cat file1 file2 file3 file4" '1:br1 -2:br1 -3:ancest -4:br1' - echo 4:br1-2 >file4 - dotest branches-12.2 "${testcvs} -q ci -m change-on-br1" \ -"Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: 1\.2\.2\.2; previous revision: 1\.2\.2\.1 -done" - dotest branches-13 "${testcvs} -q update -A" \ -'U file1 -U file2 -[UP] file3 -U file4' - dotest branches-14 "cat file1 file2 file3 file4" '1:ancest -2:ancest -3:ancest -4:trunk-2' - echo 4:trunk-3 >file4 - dotest branches-14.2 \ - "${testcvs} -q ci -m trunk-change-after-branch" \ -"Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: 1\.3; previous revision: 1\.2 -done" - dotest branches-14.3 "${testcvs} log file4" \ -" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v -Working file: file4 -head: 1\.3 -branch: -locks: strict -access list: -symbolic names: - brbr: 1\.2\.2\.1\.0\.2 - br1: 1\.2\.0\.2 -keyword substitution: kv -total revisions: 6; selected revisions: 6 -description: ----------------------------- -revision 1\.3 -date: [0-9/: ]*; author: ${username}; state: Exp; lines: ${PLUS}1 -1 -trunk-change-after-branch ----------------------------- -revision 1\.2 -date: [0-9/: ]*; author: ${username}; state: Exp; lines: ${PLUS}1 -1 -branches: 1\.2\.2; -trunk-before-branch ----------------------------- -revision 1\.1 -date: [0-9/: ]*; author: ${username}; state: Exp; -add-it ----------------------------- -revision 1\.2\.2\.2 -date: [0-9/: ]*; author: ${username}; state: Exp; lines: ${PLUS}1 -1 -change-on-br1 ----------------------------- -revision 1\.2\.2\.1 -date: [0-9/: ]*; author: ${username}; state: Exp; lines: ${PLUS}1 -1 -branches: 1\.2\.2\.1\.2; -modify ----------------------------- -revision 1\.2\.2\.1\.2\.1 -date: [0-9/: ]*; author: ${username}; state: Exp; lines: ${PLUS}1 -1 -modify -=============================================================================" - dotest_fail branches-14.4 \ - "${testcvs} diff -c -r 1.1 -r 1.3 file4" \ -"Index: file4 -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v -retrieving revision 1\.1 -retrieving revision 1\.3 -diff -c -r1\.1 -r1\.3 -\*\*\* file4 ${RFCDATE} 1\.1 ---- file4 ${RFCDATE} 1\.3 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -! 4:trunk-1 ---- 1 ---- -! 4:trunk-3" - dotest_fail branches-14.5 \ - "${testcvs} diff -c -r 1.1 -r 1.2.2.1 file4" \ -"Index: file4 -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v -retrieving revision 1\.1 -retrieving revision 1\.2\.2\.1 -diff -c -r1\.1 -r1\.2\.2\.1 -\*\*\* file4 ${RFCDATE} 1\.1 ---- file4 ${RFCDATE} 1\.2\.2\.1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1 \*\*\*\* -! 4:trunk-1 ---- 1 ---- -! 4:br1" - dotest branches-15 \ - "${testcvs} update -j 1.1.2.1 -j 1.1.2.1.2.1 file1" \ - "RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.1\.2\.1 -retrieving revision 1\.1\.2\.1\.2\.1 -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' - - dotest branches-o1 "${testcvs} -q admin -o ::brbr" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file3,v -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v -done" - cd .. - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -r first-dir - ;; - - branches2) - # More branch tests. - # Test that when updating a new subdirectory in a directory - # which was checked out on a branch, the new subdirectory is - # created on the appropriate branch. Test this when joining - # as well. - - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir trunk; cd trunk - - # Create a file. - dotest branches2-1 "${testcvs} -q co first-dir" - cd first-dir - echo "file1 first revision" > file1 - dotest branches2-2 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest branches2-3 "${testcvs} commit -m add file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - - # Tag the file. - dotest branches2-4 "${testcvs} -q tag tag1" 'T file1' - - # Make two branches. - dotest branches2-5 "${testcvs} -q rtag -b -r tag1 b1 first-dir" '' - dotest branches2-6 "${testcvs} -q rtag -b -r tag1 b2 first-dir" '' - - # Create some files and a subdirectory on branch b1. - cd ../.. - mkdir b1; cd b1 - dotest branches2-7 "${testcvs} -q co -r b1 first-dir" \ -"U first-dir/file1" - cd first-dir - echo "file2 first revision" > file2 - dotest branches2-8 "${testcvs} add file2" \ -"${PROG}"' add: scheduling file `file2'\'' for addition on branch `b1'\'' -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - mkdir dir1 - dotest branches2-9 "${testcvs} add dir1" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir1 added to the repository ---> Using per-directory sticky tag "'`'"b1'" - echo "file3 first revision" > dir1/file3 - dotest branches2-10 "${testcvs} add dir1/file3" \ -"${PROG}"' add: scheduling file `dir1/file3'\'' for addition on branch `b1'\'' -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest branches2-11 "${testcvs} -q ci -madd ." \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/Attic/file2,v <-- file2 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/Attic/file3,v -done -Checking in dir1/file3; -${CVSROOT_DIRNAME}/first-dir/dir1/Attic/file3,v <-- file3 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - # Check out the second branch, and update the working - # directory to the first branch, to make sure the right - # happens with dir1. - cd ../.. - mkdir b2; cd b2 - dotest branches2-12 "${testcvs} -q co -r b2 first-dir" \ -'U first-dir/file1' - cd first-dir - dotest branches2-13 "${testcvs} update -d -r b1 dir1" \ -"${PROG} update: Updating dir1 -U dir1/file3" - dotest branches2-14 "${testcvs} -q status" \ -"=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: b2 (branch: 1\.1\.4) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file3 Status: Up-to-date - - Working revision: 1\.1\.2\.1.* - Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/Attic/file3,v - Sticky Tag: b1 (branch: 1\.1\.2) - Sticky Date: (none) - Sticky Options: (none)" - - # FIXME: Just clobbering the directory like this is a bit - # tacky, although people generally expect it to work. Maybe - # we should release it instead. We do it a few other places - # below as well. - rm -r dir1 - dotest branches2-15 "${testcvs} update -d -j b1 dir1" \ -"${PROG} update: Updating dir1 -U dir1/file3" - # FIXCVS: The `No revision control file' stuff seems to be - # CVS's way of telling us that we're adding the file on a - # branch, and the file is not on that branch yet. This - # should be nicer. - dotest branches2-16 "${testcvs} -q status" \ -"=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: b2 (branch: 1\.1\.4) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file3 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: b2 - MISSING from RCS file! - Sticky Date: (none) - Sticky Options: (none)" - - cd ../../trunk/first-dir - dotest branches2-17 "${testcvs} update -d -P dir1" \ -"${PROG} update: Updating dir1" - dotest_fail branches2-18 "test -d dir1" - dotest branches2-19 "${testcvs} update -d -P -r b1 dir1" \ -"${PROG} update: Updating dir1 -U dir1/file3" - dotest branches2-20 "${testcvs} -q status" \ -"=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file3 Status: Up-to-date - - Working revision: 1\.1\.2\.1.* - Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/Attic/file3,v - Sticky Tag: b1 (branch: 1\.1\.2) - Sticky Date: (none) - Sticky Options: (none)" - - rm -r dir1 - dotest branches2-21 "${testcvs} update -d -P -j b1 dir1" \ -"${PROG} update: Updating dir1 -U dir1/file3" - dotest branches2-22 "${testcvs} -q status" \ -"=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file3 Status: Locally Added - - Working revision: New file! - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir1/Attic/file3,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - - cd ../.. - rm -r b1 b2 - - # Check out branch b1 twice. Crate a new directory in one - # working directory, then do a cvs update in the other - # working directory and see if the tags are right. - mkdir b1a - mkdir b1b - cd b1b - dotest branches2-23 "${testcvs} -q co -r b1 first-dir" \ -'U first-dir/file1 -U first-dir/file2 -U first-dir/dir1/file3' - cd ../b1a - dotest branches2-24 "${testcvs} -q co -r b1 first-dir" \ -'U first-dir/file1 -U first-dir/file2 -U first-dir/dir1/file3' - cd first-dir - mkdir dir2 - dotest branches2-25 "${testcvs} add dir2" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir2 added to the repository ---> Using per-directory sticky tag "'`'"b1'" - echo "file4 first revision" > dir2/file4 - dotest branches2-26 "${testcvs} add dir2/file4" \ -"${PROG}"' add: scheduling file `dir2/file4'\'' for addition on branch `b1'\'' -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest branches2-27 "${testcvs} -q commit -madd" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/dir2/Attic/file4,v -done -Checking in dir2/file4; -${CVSROOT_DIRNAME}/first-dir/dir2/Attic/file4,v <-- file4 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - cd ../../b1b/first-dir - dotest branches2-28 "${testcvs} update -d dir2" \ -"${PROG} update: Updating dir2 -U dir2/file4" - cd dir2 - dotest branches2-29 "${testcvs} -q status" \ -"=================================================================== -File: file4 Status: Up-to-date - - Working revision: 1\.1\.2\.1.* - Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/dir2/Attic/file4,v - Sticky Tag: b1 (branch: 1\.1\.2) - Sticky Date: (none) - Sticky Options: (none)" - dotest branches2-30 "cat CVS/Tag" 'Tb1' - - # Test update -A on a subdirectory - cd .. - rm -r dir2 - dotest branches2-31 "${testcvs} update -A -d dir2" \ -"${PROG} update: Updating dir2" - cd dir2 - dotest branches2-32 "${testcvs} -q status" '' - dotest_fail branches2-33 "test -f CVS/Tag" - - # Add a file on the trunk. - echo "file5 first revision" > file5 - dotest branches2-34 "${testcvs} add file5" \ -"${PROG}"' add: scheduling file `file5'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest branches2-35 "${testcvs} -q commit -madd" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/dir2/file5,v -done -Checking in file5; -${CVSROOT_DIRNAME}/first-dir/dir2/file5,v <-- file5 -initial revision: 1\.1 -done" - - cd ../../../trunk/first-dir - dotest branches2-36 "${testcvs} -q update -d dir2" 'U dir2/file5' - cd dir2 - dotest branches2-37 "${testcvs} -q status" \ -"=================================================================== -File: file5 Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/dir2/file5,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest_fail branches2-38 "test -f CVS/status" - - cd ../../.. - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -r trunk b1a b1b - ;; - - tagc) - # Test the tag -c option. - mkdir 1; cd 1 - dotest tagc-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest tagc-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch file1 file2 - dotest tagc-3 "${testcvs} add file1 file2" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest tagc-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - dotest tagc-5 "${testcvs} -q tag -c tag1" \ -"T file1 -T file2" - touch file1 file2 - dotest tagc-6 "${testcvs} -q tag -c tag2" \ -"T file1 -T file2" - # Avoid timestamp granularity bugs (FIXME: CVS should be - # doing the sleep, right?). - sleep 1 - echo myedit >>file1 - dotest tagc-6a "${testcvs} rm -f file2" \ -"${PROG} remove: scheduling .file2. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - touch file3 - dotest tagc-6b "${testcvs} add file3" \ -"${PROG} add: scheduling file .file3. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest_fail tagc-7 "${testcvs} -q tag -c tag3" \ -"${PROG} tag: file1 is locally modified -${PROG} tag: file2 is locally modified -${PROG} tag: file3 is locally modified -${PROG} \[tag aborted\]: correct the above errors first!" - cd ../.. - mkdir 2 - cd 2 - dotest tagc-8 "${testcvs} -q co first-dir" \ -"U first-dir/file1 -U first-dir/file2" - cd ../1/first-dir - dotest tagc-9 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done -Removing file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: delete; previous revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file3,v -done -Checking in file3; -${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3 -initial revision: 1\.1 -done" - cd ../../2/first-dir - dotest tagc-10 "${testcvs} -q tag -c tag4" \ -"${PROG} tag: file2 is no longer in the repository -T file1 -T file2" - cd ../.. - - rm -r 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - update-p) - # Make sure `cvs update -p -rT FILE' works from a branch when - # FILE is already on the trunk and is being added to that branch. - - mkdir 1; cd 1 - module=x - - echo > unused-file - - # Create the module. - dotest update-p-1 \ - "$testcvs -Q import -m. $module X Y" '' - - file=F - # Check it out and tag it. - dotest update-p-2 "$testcvs -Q co $module" '' - cd $module - dotest update-p-3 "$testcvs -Q tag -b B" '' - echo v1 > $file - dotest update-p-4 "$testcvs -Q add $file" '' - dotest update-p-5 "$testcvs -Q ci -m. $file" \ -"RCS file: ${CVSROOT_DIRNAME}/$module/$file,v -done -Checking in $file; -${CVSROOT_DIRNAME}/$module/$file,v <-- $file -initial revision: 1\.1 -done" - dotest update-p-6 "$testcvs -Q tag T $file" '' - dotest update-p-7 "$testcvs -Q update -rB" '' - - # This merge effectively adds file F on branch B. - dotest update-p-8 "$testcvs -Q update -jT" '' - - # Before the fix that prompted the addition of this test, - # the following command would fail with this diagnostic: - # cvs update: conflict: F created independently by second party - dotest update-p-9 "$testcvs update -p -rT $file" \ -"=================================================================== -Checking out $file -RCS: ${CVSROOT_DIRNAME}/$module/$file,v -VERS: 1\.1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -v1" - - # Repeat the above, but with $file removed. - # This exercises a slightly different code path. - rm $file - # Before the fix that prompted the addition of this test, - # the following command would fail with this diagnostic: - # cvs update: warning: new-born F has disappeared - dotest update-p-10 "$testcvs update -p -rT $file" \ -"=================================================================== -Checking out $file -RCS: ${CVSROOT_DIRNAME}/$module/$file,v -VERS: 1\.1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -v1" - - # Exercise yet another code path: - # the one that involves reviving a `dead' file. - # And a little more, for good measure... - touch new - dotest update-p-a1 "$testcvs -Q add new" '' - dotest update-p-a2 "$testcvs -Q update -p new" '' - dotest update-p-a3 "$testcvs -Q rm -f new" '' - - # Both an update -A, *and* the following update are required - # to return to the state of being on the trunk with a $file - # that we can then remove. - dotest update-p-undead-0 "$testcvs update -A" \ -"$PROG update: Updating \. -$PROG update: warning: new-born $file has disappeared -[UP] unused-file" - dotest update-p-undead-1 "$testcvs update" \ -"${PROG} update: Updating \. -U $file" - dotest update-p-undead-2 "$testcvs -Q update -p -rT $file" v1 - dotest update-p-undead-3 "$testcvs -Q rm -f $file" '' - dotest update-p-undead-4 "$testcvs -Q update -p -rT $file" v1 - dotest update-p-undead-5 "$testcvs -Q ci -m. $file" \ -"Removing $file; -${CVSROOT_DIRNAME}/$module/$file,v <-- $file -new revision: delete; previous revision: 1\.1 -done" - dotest update-p-undead-6 "$testcvs -Q update -p -rT $file" v1 - echo v2 > $file - dotest update-p-undead-7 "$testcvs -Q update -p -rT $file" v1 - dotest update-p-undead-8 "$testcvs add $file" \ -"${PROG} add: Re-adding file .$file. (in place of dead revision 1\.2)\. -${PROG} add: use .${PROG} commit. to add this file permanently" - - dotest update-p-undead-9 "$testcvs -Q update -p -rT $file" v1 - - cd ../.. - rm -rf 1 - rm -rf ${CVSROOT_DIRNAME}/$module - ;; - - tagf) - # More tagging tests, including using tag -F -B to convert a - # branch tag to a regular tag and recovering thereof. - - # Setup; check in first-dir/file1 - mkdir 1; cd 1 - dotest tagf-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest tagf-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch file1 file2 - dotest tagf-3 "${testcvs} add file1 file2" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest tagf-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - - # Now create a branch and commit a revision there. - dotest tagf-5 "${testcvs} -q tag -b br" "T file1 -T file2" - dotest tagf-6 "$testcvs -q update -r br" \ -'U file1 -U file2' - echo brmod >> file1 - echo brmod >> file2 - dotest tagf-7 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - # Here we try to make it a non-branch tag, but will - # succeed in getting only warnings, even with -F - # because converting a branch tag to non-branch - # is potentially catastrophic. - dotest tagf-8a "${testcvs} -q tag -F br" \ -"${PROG} tag: file1: Not moving branch tag .br. from 1\.1\.2\.1 to 1\.1\\.2\.1\. -${PROG} tag: file2: Not moving branch tag .br. from 1\.1\.2\.1 to 1\.1\.2\.1\." - # however, if we *really* are sure we want to move a branch tag, - # "-F -B" will do the trick - dotest tagf-8 "${testcvs} -q tag -F -B br" "T file1 -T file2" - echo moremod >> file1 - echo moremod >> file2 - dotest tagf-9 "${testcvs} -q status -v file1" \ -"=================================================================== -File: file1 Status: Locally Modified - - Working revision: 1\.1\.2\.1.* - Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: br (revision: 1\.1\.2\.1) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - br (revision: 1\.1\.2\.1)" - - # Now, how do we recover? - dotest tagf-10 "${testcvs} -q tag -d br" "D file1 -D file2" - # This creates a new branch, 1.1.4. See the code in RCS_magicrev - # which will notice that there is a (non-magic) 1.1.2 and thus - # skip that number. - dotest tagf-11 "${testcvs} -q tag -r 1.1 -b br file1" "T file1" - # Fix it with admin -n (cf admin-18, admin-26-4). - dotest tagf-12 "${testcvs} -q admin -nbr:1.1.2 file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - # Another variation on the file2 test would be to use two working - # directories so that the update -r br would need to - # a merge to get from 1.1.2.1 to the head of the 1.1.2 branch. - dotest tagf-13 "${testcvs} -q update -r br" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.1\.2\.1 -retrieving revision 1\.1 -Merging differences between 1\.1\.2\.1 and 1\.1 into file1 -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in file1 -C file1 -M file2" - # CVS is giving a conflict because we are trying to get back to - # 1.1.4. I'm not sure why it is a conflict rather than just - # "M file1". - dotest tagf-14 "cat file1" \ -"<<<<<<< file1 -brmod -moremod -[=]====== -[>]>>>>>> 1\.1" - echo resolve >file1 - dotest tagf-15 "${testcvs} -q ci -m recovered" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.4\.1; previous revision: 1\.1 -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 -done" - # try accidentally deleting branch tag, "tag -d" - dotest_fail tagf-16 "${testcvs} tag -d br" \ -"${PROG} tag: Untagging \. -${PROG} tag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file1,v.\. -${PROG} tag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file2,v.\." - # try accidentally deleting branch tag, "rtag -d" - dotest_fail tagf-17 "${testcvs} rtag -d br first-dir" \ -"${PROG} rtag: Untagging first-dir -${PROG} rtag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file1,v.\. -${PROG} rtag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file2,v.\." - # try accidentally converting branch tag to non-branch tag "tag -F" - dotest tagf-18 "${testcvs} tag -r1.1 -F br file1" \ -"${PROG} tag: file1: Not moving branch tag .br. from 1\.1\.4\.1 to 1\.1\." - # try accidentally converting branch tag to non-branch tag "rtag -F" - dotest tagf-19 "${testcvs} rtag -r1.1 -F br first-dir" \ -"${PROG} rtag: Tagging first-dir -${PROG} rtag: first-dir/file1: Not moving branch tag .br. from 1\.1\.4\.1 to 1\.1\. -${PROG} rtag: first-dir/file2: Not moving branch tag .br. from 1\.1\.2\.2 to 1\.1\." - # create a non-branch tag - dotest tagf-20 "${testcvs} rtag regulartag first-dir" \ -"${PROG} rtag: Tagging first-dir" - # try accidentally converting non-branch tag to branch tag (tag -F -B -b) - dotest tagf-21 "${testcvs} tag -F -B -b regulartag file1" \ -"${PROG} tag: file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.4\.1\.0\.2 due to .-B. option\." - # try accidentally converting non-branch tag to branch rtag (rtag -F -B -b) - dotest tagf-22 "${testcvs} rtag -F -B -b regulartag first-dir" \ -"${PROG} rtag: Tagging first-dir -${PROG} rtag: first-dir/file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.0\.6 due to .-B. option\. -${PROG} rtag: first-dir/file2: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.0\.4 due to .-B. option\." - # Try accidentally deleting non-branch: (tag -d -B) - dotest_fail tagf-23 "${testcvs} tag -d -B regulartag file1" \ -"${PROG} tag: Not removing non-branch tag .regulartag. from .${CVSROOT_DIRNAME}/first-dir/file1,v. due to .-B. option\." - # Try accidentally deleting non-branch: (rtag -d -B) - dotest_fail tagf-24 \ - "${testcvs} rtag -d -B regulartag first-dir" \ -"${PROG} rtag: Untagging first-dir -${PROG} rtag: Not removing non-branch tag .regulartag. from .${CVSROOT_DIRNAME}/first-dir/file1,v. due to .-B. option\. -${PROG} rtag: Not removing non-branch tag .regulartag. from .${CVSROOT_DIRNAME}/first-dir/file2,v. due to .-B. option\." - - # the following tests (throught the next commit) keep moving the same - # tag back and forth between 1.1.6 & 1.1.8 in file1 and between - # 1.1.4 and 1.1.6 in file2 since nothing was checked in on some of - # these branches and CVS only tracks branches via tags unless they contain data. - - # try intentionally converting non-branch tag to branch tag (tag -F -b) - dotest tagf-25a "${testcvs} tag -F -b regulartag file1" "T file1" - # try intentionally moving a branch tag to a newly created branch (tag -F -b -B) - dotest tagf-25b "${testcvs} tag -F -B -b -r1.1 regulartag file1" \ -"T file1" - # try intentionally converting mixed tags to branch tags (rtag -F -b) - dotest tagf-26a "${testcvs} rtag -F -b regulartag first-dir" \ -"${PROG} rtag: Tagging first-dir -${PROG} rtag: first-dir/file1: Not moving branch tag .regulartag. from 1\.1 to 1\.1\.0\.8\." - # try intentionally converting a branch to a new branch tag (rtag -F -b -B) - dotest tagf-26b "${testcvs} rtag -F -B -b -r1.1 regulartag first-dir" \ -"${PROG} rtag: Tagging first-dir" - # update to our new branch - dotest tagf-27 "${testcvs} update -r regulartag" \ -"${PROG} update: Updating \. -U file1 -U file2" - # commit some changes and see that all rev numbers look right - echo changes >> file1 - echo changes >> file2 - dotest tagf-28 "${testcvs} ci -m changes" \ -"${PROG} [a-z]*: Examining \. -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.8\.1; previous revision: 1\.1 -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.1\.6\.1; previous revision: 1\.1 -done" - # try intentional branch to non-branch (tag -F -B) - dotest tagf-29 "${testcvs} tag -F -B -r1.1 regulartag file1" \ -"T file1" - # try non-branch to non-branch (tag -F -B) - dotest tagf-29a "${testcvs} tag -F -B -r br regulartag file1" \ -"${PROG} tag: file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.4\.1 due to .-B. option\." - # try mixed-branch to non-branch (rtag -F -B ) - dotest tagf-29b "${testcvs} rtag -F -B -r br regulartag first-dir" \ -"${PROG} rtag: Tagging first-dir -${PROG} rtag: first-dir/file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.4\.1 due to .-B. option\." - # at this point, regulartag is a regular tag within - # file1 and file2 - - # try intentional branch to non-branch (rtag -F -B) - dotest tagf-30 "${testcvs} rtag -F -B -r1.1 br first-dir" \ -"${PROG} rtag: Tagging first-dir" - # create a branch tag so we can try to delete it. - dotest tagf-31 "${testcvs} rtag -b brtag first-dir" \ -"${PROG} rtag: Tagging first-dir" - - # try intentinal deletion of branch tag (tag -d -B) - dotest tagf-32 "${testcvs} tag -d -B brtag file1" "D file1" - # try intentinal deletion of branch tag (rtag -d -B) - dotest tagf-33 "${testcvs} rtag -d -B brtag first-dir" \ -"${PROG} rtag: Untagging first-dir" - - cd ../.. - - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - tag-log) - # Test log output for tags - mkdir 1; cd 1 - dotest tag-log-init-1 "$testcvs -q co -l ." - mkdir first-dir - dotest tag-log-init-2 "$testcvs add first-dir" \ -"Directory $CVSROOT_DIRNAME/first-dir added to the repository" - cd first-dir - touch file1 - dotest tag-log-init-3 "$testcvs add file1" \ -"${PROG}"' add: scheduling file `file1'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest tag-log-init-4 "$testcvs -Q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - - dotest tag-log-1 "$testcvs -Q tag mytag file1" '' - dotest tag-log-2 "$testcvs log -N file1" \ -" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -add -=============================================================================" - dotest tag-log-3 "$testcvs log -N -n file1" \ -" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - mytag: 1\.1 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -add -=============================================================================" - dotest tag-log-4 "$testcvs log file1" \ -" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - mytag: 1\.1 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -add -=============================================================================" - dotest tag-log-5 "$testcvs log -n file1" \ -" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - mytag: 1\.1 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -add -=============================================================================" - - cd ../.. - rm -fr 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - tag-space) - # Test tags with spaces in the names. - # - # Prior to releases 1.11.18 & 1.12.10, some commands used with - # tags with spaces in the names could hang CVS. - - # Setup; check in first-dir/file1 - mkdir 1; cd 1 - dotest tag-space-init-1 "$testcvs -q co -l ." - mkdir first-dir - dotest tag-space-init-2 "$testcvs add first-dir" \ -"Directory $CVSROOT_DIRNAME/first-dir added to the repository" - cd first-dir - touch file1 - dotest tag-space-init-3 "$testcvs add file1" \ -"$PROG add: scheduling file \`file1' for addition -$PROG add: use '$PROG commit' to add this file permanently" - dotest tag-space-init-4 "$testcvs -Q ci -m add" \ -"RCS file: $CVSROOT_DIRNAME/first-dir/file1,v -done -Checking in file1; -$CVSROOT_DIRNAME/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - - # Reportedly, the following two tags make it past WinCVS. - dotest_fail tag-space-1 "$testcvs tag ' spacetag '" \ -"$PROG \[tag aborted\]: tag \` spacetag ' must start with a letter" - dotest_fail tag-space-2 "$testcvs tag 'spacetag '" \ -"$PROG \[tag aborted\]: tag \`spacetag ' has non-visible graphic characters" - - if $remote; then - # Verify that this isn't a client check. - dotest tag-space-3 "$testcvs server" \ -"E $PROG \[tag aborted\]: tag \` spacetag ' must start with a letter -error " <<EOF -Root $CVSROOT_DIRNAME -UseUnchanged -Argument -- -Argument spacetag -Directory . -$CVSROOT_DIRNAME/first-dir -Entry /file1/1.1/// -Unchanged file1 -tag -EOF - - dotest tag-space-4 "$testcvs server" \ -"E $PROG \[tag aborted\]: tag \`spacetag ' has non-visible graphic characters -error " <<EOF -Root $CVSROOT_DIRNAME -UseUnchanged -Argument -- -Argument spacetag -Directory . -$CVSROOT_DIRNAME/first-dir -Entry /file1/1.1/// -Unchanged file1 -tag -EOF - fi # $remote - - # Any number of normal tags and branches were handled correctly. - dotest tag-space-5 "$testcvs -Q tag t1" - dotest tag-space-5b "$testcvs -Q tag t2" - dotest tag-space-5c "$testcvs -Q tag -b b1" - - cd ../.. - mkdir 2; cd 2 - - # But once a vendor branch exists, it's all over. - mkdir project; cd project - touch file1 - dotest tag-space-init-4 \ -"$testcvs -Q import -mimport second-dir VENDOR RELEASE" - - cd .. - - dotest_fail tag-space-6 "$testcvs -Q co -r ' spacetag ' first-dir" \ -"$PROG \[checkout aborted\]: tag \` spacetag ' must start with a letter" - - # But when any files were imported, this test hung prior to CVS - # versions 1.11.18 & 1.12.10. - dotest_fail tag-space-7 "$testcvs -Q co -r ' spacetag ' second-dir" \ -"$PROG \[checkout aborted\]: tag \` spacetag ' must start with a letter" - - if $remote; then - # I based the client input in the next two tests on actual input - # from WinCVS 1.2. - dotest tag-space-8 "$testcvs server" \ -"E $PROG \[checkout aborted\]: tag \` spacetag ' must start with a letter -error " <<EOF -Root $CVSROOT_DIRNAME -Argument -P -Argument -r -Argument spacetag -Argument first-dir -Directory . -$CVSROOT_DIRNAME -co -EOF - - # Verify the test is not on the client side. - dotest tag-space-9 "$testcvs server" \ -"E $PROG \[checkout aborted\]: tag \` spacetag ' must start with a letter -error " <<EOF -Root $CVSROOT_DIRNAME -Argument -P -Argument -r -Argument spacetag -Argument second-dir -Directory . -$CVSROOT_DIRNAME -co -EOF - fi # $remote - - dotest tag-space-10 "$testcvs -Q co second-dir" - cd second-dir - - # This test would also hang. - dotest_fail tag-space-11 "$testcvs -Q up -r ' spacetag '" \ -"$PROG \[update aborted\]: tag \` spacetag ' must start with a letter" - - if $remote; then - dotest tag-space-12 "$testcvs server" \ -"E $PROG \[update aborted\]: tag \` spacetag ' must start with a letter -error " <<EOF -Root $CVSROOT_DIRNAME -Argument -r -Argument spacetag -Argument -u -Argument -- -Directory . -$CVSROOT_DIRNAME -Unchanged file1 -update -EOF - fi # $remote - - # I'm skipping tests for other commands that may have had the same - # problem. Hopefully, if a new issue arises, one of the above tests - # will catch the problem. - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd ../.. - rm -r 1 2 - rm -rf $CVSROOT_DIRNAME/first-dir $CVSROOT_DIRNAME/second-dir - ;; - - rcslib) - # Test librarification of RCS. - # First: test whether `cvs diff' handles $Name expansion - # correctly. We diff two revisions with their symbolic tags; - # neither tag should be expanded in the output. Also diff - # one revision with the working copy. - - mkdir ${CVSROOT_DIRNAME}/first-dir - dotest rcsdiff-1 "${testcvs} -q co first-dir" '' - cd first-dir - echo "I am the first foo, and my name is $""Name$." > foo.c - dotest rcsdiff-2 "${testcvs} add -m new-file foo.c" \ -"${PROG} add: scheduling file .foo\.c. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest rcsdiff-3 "${testcvs} commit -m rev1 foo.c" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v -done -Checking in foo\.c; -${CVSROOT_DIRNAME}/first-dir/foo.c,v <-- foo\.c -initial revision: 1\.1 -done" - dotest rcsdiff-4 "${testcvs} tag first foo.c" "T foo\.c" - dotest rcsdiff-5 "${testcvs} update -p -r first foo.c" \ -"=================================================================== -Checking out foo\.c -RCS: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v -VERS: 1\.1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -I am the first foo, and my name is \$""Name: first \$\." - - echo "I am the second foo, and my name is $""Name$." > foo.c - dotest rcsdiff-6 "${testcvs} commit -m rev2 foo.c" \ -"Checking in foo\.c; -${CVSROOT_DIRNAME}/first-dir/foo\.c,v <-- foo\.c -new revision: 1\.2; previous revision: 1\.1 -done" - dotest rcsdiff-7 "${testcvs} tag second foo.c" "T foo\.c" - dotest rcsdiff-8 "${testcvs} update -p -r second foo.c" \ -"=================================================================== -Checking out foo\.c -RCS: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v -VERS: 1\.2 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -I am the second foo, and my name is \$""Name: second \$\." - - dotest_fail rcsdiff-9 "${testcvs} diff -r first -r second" \ -"${PROG} diff: Diffing \. -Index: foo\.c -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v -retrieving revision 1\.1 -retrieving revision 1\.2 -diff -r1\.1 -r1\.2 -1c1 -< I am the first foo, and my name is \$""Name: \$\. ---- -> I am the second foo, and my name is \$""Name: \$\." - - echo "I am the once and future foo, and my name is $""Name$." > foo.c - dotest_fail rcsdiff-10 "${testcvs} diff -r first" \ -"${PROG} diff: Diffing \. -Index: foo\.c -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v -retrieving revision 1\.1 -diff -r1\.1 foo\.c -1c1 -< I am the first foo, and my name is \$""Name: \$\. ---- -> I am the once and future foo, and my name is \$""Name\$\." - - # Test handling of libdiff options. diff gets quite enough - # of a workout elsewhere in sanity.sh, so we assume that it's - # mostly working properly if it passes all the other tests. - # The main one we want to try is regex handling, since we are - # using CVS's regex matcher and not diff's. - - cat >rgx.c <<EOF -test_regex (whiz, bang) -{ -foo; -bar; -baz; -grumble; -} -EOF - - dotest rcslib-diffrgx-1 "${testcvs} -q add -m '' rgx.c" \ -"${PROG} add: use .${PROG} commit. to add this file permanently" - dotest rcslib-diffrgx-2 "${testcvs} -q ci -m '' rgx.c" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/rgx\.c,v -done -Checking in rgx\.c; -${CVSROOT_DIRNAME}/first-dir/rgx\.c,v <-- rgx\.c -initial revision: 1\.1 -done" - cat >rgx.c <<EOF -test_regex (whiz, bang) -{ -foo; -bar; -baz; -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" \ -"Index: rgx\.c -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/rgx\.c,v -retrieving revision 1\.1 -diff -c -F \.\* ( -r1\.1 rgx\.c -\*\*\* rgx\.c ${RFCDATE} 1\.1 ---- rgx\.c ${RFCDATE} -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* test_regex (whiz, bang) -\*\*\* 3,7 \*\*\*\* - foo; - bar; - baz; -! grumble; - } ---- 3,7 ---- - foo; - bar; - baz; -! mumble; - }" - - # Tests of rcsmerge/diff3. Merge operations get a good general - # workout elsewhere; we want to make sure that options are still - # handled properly. Try merging two branches with -kv, to test - # both -j and -k switches. - - cd .. - - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -r first-dir - - mkdir 1; cd 1 - dotest rcslib-merge-1 "${testcvs} -q co -l ." "" - mkdir first-dir - dotest rcslib-merge-2 "${testcvs} -q add first-dir" \ -"Directory ${CVSROOT_DIRNAME}.*/first-dir added to the repository" - cd ..; rm -r 1 - - dotest rcslib-merge-3 "${testcvs} -q co first-dir" "" - cd first-dir - - echo '$''Revision$' > file1 - echo '2' >> file1 - echo '3' >> file1 - dotest rcslib-merge-4 "${testcvs} -q add file1" \ -"${PROG} add: use .${PROG} commit. to add this file permanently" - dotest rcslib-merge-5 "${testcvs} -q commit -m '' file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - sed -e 's/2/two/' file1 > f; mv f file1 - dotest rcslib-merge-6 "${testcvs} -q commit -m '' file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - dotest rcslib-merge-7 "${testcvs} -q tag -b -r 1.1 patch1" "T file1" - dotest rcslib-merge-8 "${testcvs} -q update -r patch1" "[UP] file1" - dotest rcslib-merge-9 "${testcvs} -q status" \ -"=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: patch1 (branch: 1\.1\.2) - Sticky Date: (none) - Sticky Options: (none)" - dotest rcslib-merge-10 "cat file1" \ -'$''Revision: 1\.1 $ -2 -3' - sed -e 's/3/three/' file1 > f; mv f file1 - dotest rcslib-merge-11 "${testcvs} -q commit -m '' file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - dotest rcslib-merge-12 "${testcvs} -q update -kv -j1.2" \ -"U file1 -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into file1 -rcsmerge: warning: conflicts during merge" - dotest rcslib-merge-13 "cat file1" \ -"<<<<<<< file1 -1\.1\.2\.1 -2 -three -[=]====== -1\.2 -two -3 -[>]>>>>>> 1\.2" - - # Test behavior of symlinks in the repository. - if test -n "$remotehost"; then - # Create the link on the remote system. This is because Cygwin's - # Windows support creates *.lnk files for Windows. When creating - # these in an SMB share from UNIX, these links won't work from the - # UNIX side. - dotest rcslib-symlink-1remotehost "${CVS_RSH} $remotehost 'ln -s file1,v ${CVSROOT_DIRNAME}/first-dir/file2,v'" - else - dotest rcslib-symlink-1 "ln -s file1,v ${CVSROOT_DIRNAME}/first-dir/file2,v" - fi - dotest rcslib-symlink-2 "${testcvs} update file2" "U file2" - echo "This is a change" >> file2 - dotest rcslib-symlink-3 "${testcvs} ci -m because file2" \ -"Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file2 -new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 -done" - - # Switch as for rcslib-symlink-1 - if test -n "$remotehost"; then - dotest rcslib-symlink-4 "$CVS_RSH $remotehost 'ls -l $CVSROOT_DIRNAME/first-dir/file2,v'" \ -".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v" - else - dotest rcslib-symlink-4 "ls -l $CVSROOT_DIRNAME/first-dir/file2,v" \ -".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v" - fi - - # CVS was failing to check both the symlink and the file - # for timestamp changes for a while. Test that. - rm file1 - dotest rcslib-symlink-3a "${testcvs} -q up file1" \ -"${PROG} update: warning: file1 was lost -U file1" - echo "This is a change" >> file1 - dotest rcslib-symlink-3b "${testcvs} ci -m because file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.[0-9]*; previous revision: 1\.1\.2\.[0-9]* -done" - dotest rcslib-symlink-3c "${testcvs} update file2" "[UP] file2" - - echo some new text >file3 - dotest rcslib-symlink-3d "${testcvs} -Q add file3" '' - dotest rcslib-symlink-3e "${testcvs} -Q ci -mtest file3" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v -done -Checking in file3; -${CVSROOT_DIRNAME}/first-dir/Attic/file3,v <-- file3 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - rm -f ${CVSROOT_DIRNAME}/first-dir/file2,v - # As for rcslib-symlink-1 - if test -n "$remotehost"; then - dotest rcslib-symlink-3f "$CVS_RSH $remotehost 'ln -s Attic/file3,v ${CVSROOT_DIRNAME}/first-dir/file2,v'" - else - dotest rcslib-symlink-3f "ln -s Attic/file3,v ${CVSROOT_DIRNAME}/first-dir/file2,v" - fi - - dotest rcslib-symlink-3g "${testcvs} update file2" "U file2" - - # restore the link to file1 for the following tests - dotest rcslib-symlink-3i "${testcvs} -Q rm -f file3" '' - dotest rcslib-symlink-3j "${testcvs} -Q ci -mwhatever file3" \ -"Removing file3; -${CVSROOT_DIRNAME}/first-dir/Attic/file3,v <-- file3 -new revision: delete; previous revision: 1\.1\.2\.1 -done" - rm -f ${CVSROOT_DIRNAME}/first-dir/file2,v - rm -f ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v - # As for rcslib-symlink-1 - if test -n "$remotehost"; then - dotest rcslib-symlink-3h "$CVS_RSH $remotehost 'ln -s file1,v ${CVSROOT_DIRNAME}/first-dir/file2,v'" - else - dotest rcslib-symlink-3h "ln -s file1,v ${CVSROOT_DIRNAME}/first-dir/file2,v" - fi - - # Test 5 reveals a problem with having symlinks in the - # repository. CVS will try to tag both of the files - # separately. After processing one, it will do the same - # operation to the other, which is actually the same file, - # so the tag will already be there. FIXME: do we bother - # changing operations to notice cases like this? This - # strikes me as a difficult problem. -Noel - dotest rcslib-symlink-5 "${testcvs} tag the_tag" \ -"${PROG} tag: Tagging . -T file1 -W file2 : the_tag already exists on version 1.1.2.3 : NOT MOVING tag to version 1.1.2.1" - # As for rcslib-symlink-1 - if test -n "$remotehost"; then - dotest rcslib-symlink-6 "$CVS_RSH $remotehost 'ls -l $CVSROOT_DIRNAME/first-dir/file2,v'" \ -".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v" - else - dotest rcslib-symlink-6 "ls -l $CVSROOT_DIRNAME/first-dir/file2,v" \ -".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v" - fi - - # Symlinks tend to interact poorly with the Attic. - cd .. - mkdir 2; cd 2 - dotest rcslib-symlink-7 "${testcvs} -q co first-dir" \ -"U first-dir/file1 -U first-dir/file2" - cd first-dir - dotest rcslib-symlink-8 "${testcvs} rm -f file2" \ -"${PROG} remove: scheduling .file2. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest rcslib-symlink-9 "${testcvs} -q ci -m rm-it" \ -"Removing file2; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file2 -new revision: delete; previous revision: 1\.2 -done" - # OK, why this message happens twice is relatively clear - # (the check_* and rtag_* calls to start_recursion). - # Why it happens a third time I didn't try to find out. - dotest rcslib-symlink-10 \ -"${testcvs} -q rtag -b -r the_tag brtag first-dir" \ -"${PROG} rtag: could not read RCS file for file2 -${PROG} rtag: could not read RCS file for first-dir/file2 -${PROG} rtag: could not read RCS file for first-dir/file2" - - # Restore file1 for the next test. - dotest rcslib-long-symlink-init-1 "$testcvs -Q up -A" - dotest rcslib-long-symlink-init-2 "$testcvs -Q add file1" - dotest rcslib-long-symlink-init-3 "$testcvs -Q ci -mback" \ -"Checking in file1; -$CVSROOT_DIRNAME/first-dir/file1,v <-- file1 -new revision: 1\.4; previous revision: 1\.3 -done" - - cd ../.. # $TESTDIR - - # CVS has a hard-coded default link path size of 127 characters. - # Make sure it knows how to exceed that. - longpath=$CVSROOT_DIRNAME - count=0 - while test $count -lt 10; do - count=`expr $count + 1` - longpath=$longpath/123456789012345678901234567890 - mkdir $longpath - done - cp $CVSROOT_DIRNAME/first-dir/file1,v $longpath - mkdir $CVSROOT_DIRNAME/second-dir - - # Switch as for rcslib-symlink-1 - if test -n "$remotehost"; then - dotest rcslib-long-symlink-1rh \ -"$CVS_RSH $remotehost 'ln -s $longpath/file1,v $CVSROOT_DIRNAME/second-dir/fileX,v'" - else - dotest rcslib-long-symlink-1 \ -"ln -s $longpath/file1,v $CVSROOT_DIRNAME/second-dir/fileX,v" - fi - - dotest rcslib-long-symlink-2 "$testcvs co second-dir" \ -"$PROG checkout: Updating second-dir -U second-dir/fileX" - - cd second-dir - echo change-it >>fileX - - # Writes actually cause symlinks to be resolved. - dotest rcslib-long-symlink-3 "$testcvs -q ci -mwrite-it" \ -"Checking in fileX; -$CVSROOT_DIRNAME/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/file1,v <-- fileX -new revision: 1\.5; previous revision: 1\.4 -done" - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd .. - # Must remove the symlink first. Samba doesn't appear to show - # broken symlink across the SMB share, and rm -rf by itself - # will remove file1,v first and leave file2,v a broken link and the - # rm -rf will fail since it doesn't find file2,v and it still gets - # directory not empty errors removing cvsroot/first-dir. - # - # I'm not sure why I need to do this on $remotehost. The rm above - # rcslib-symlink-3j works fine, but the next one doesn't unless run - # remotely under Cygwin and using a TESTDIR on a Samba share. - if test -n "$remotehost"; then - $CVS_RSH $remotehost \ -"rm -f $CVSROOT_DIRNAME/first-dir/file2,v $CVSROOT_DIRNAME/second-dir/fileX,v" - fi - rm -rf $CVSROOT_DIRNAME/first-dir $CVSROOT_DIRNAME/second-dir \ - $CVSROOT_DIRNAME/123456789012345678901234567890 - rm -r first-dir second-dir 2 - ;; - - multibranch) - # Test the ability to have several branchpoints coming off the - # same revision. - mkdir ${CVSROOT_DIRNAME}/first-dir - dotest multibranch-1 "${testcvs} -q co first-dir" '' - cd first-dir - echo 1:trunk-1 >file1 - dotest multibranch-2 "${testcvs} add file1" \ -"${PROG}"' add: scheduling file `file1'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest_lit multibranch-3 "${testcvs} -q ci -m add-it" <<HERE -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1.1 -done -HERE - dotest multibranch-4 "${testcvs} tag -b br1" \ -"${PROG} tag: Tagging \. -T file1" - dotest multibranch-5 "${testcvs} tag -b br2" \ -"${PROG} tag: Tagging \. -T file1" - dotest multibranch-6 "$testcvs -q update -r br1" '[UP] file1' - echo on-br1 >file1 - dotest multibranch-7 "${testcvs} -q ci -m modify-on-br1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - dotest multibranch-8 "${testcvs} -q update -r br2" '[UP] file1' - echo br2 adds a line >>file1 - dotest multibranch-9 "${testcvs} -q ci -m modify-on-br2" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.4\.1; previous revision: 1\.1 -done" - dotest multibranch-10 "${testcvs} -q update -r br1" '[UP] file1' - dotest multibranch-11 "cat file1" 'on-br1' - dotest multibranch-12 "${testcvs} -q update -r br2" '[UP] file1' - dotest multibranch-13 "cat file1" '1:trunk-1 -br2 adds a line' - - dotest multibranch-14 "${testcvs} log file1" \ -" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - br2: 1\.1\.0\.4 - br1: 1\.1\.0\.2 -keyword substitution: kv -total revisions: 3; selected revisions: 3 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -branches: 1\.1\.2; 1\.1\.4; -add-it ----------------------------- -revision 1\.1\.4\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -modify-on-br2 ----------------------------- -revision 1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -1 -modify-on-br1 -=============================================================================" - cd .. - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -r first-dir - ;; - - import) # test death after import - # Tests of "cvs import": - # basic2 - # rdiff -- imports with keywords - # import -- more tests of imports with keywords - # importb -- -b option. - # importc -- bunch o' files in bunch o' directories - # modules3 - # mflag -- various -m messages - # ignore -- import and cvsignore - # binwrap -- import and -k wrappers - # info -- imports which are rejected by verifymsg - # head -- intended to test vendor branches and HEAD, - # although it doesn't really do it yet. - # import-CVS -- refuse to import directories named "CVS". - # import-quirks -- short tests of import quirks. - - # import - mkdir import-dir ; cd import-dir - - for i in 1 2 3 4 ; do - echo imported file"$i" > imported-f"$i" - done - - # This directory should be on the default ignore list, - # so it shouldn't get imported. - mkdir RCS - echo ignore.me >RCS/ignore.me - - echo 'import should not expand $''Id$' >>imported-f2 - cp imported-f2 ../imported-f2-orig.tmp - - dotest_sort import-96 \ -"${testcvs} import -m first-import first-dir vendor-branch junk-1_0" \ -" - -I first-dir/RCS -N first-dir/imported-f1 -N first-dir/imported-f2 -N first-dir/imported-f3 -N first-dir/imported-f4 -No conflicts created by this import" - - dotest import-96.5 "cmp ../imported-f2-orig.tmp imported-f2" '' - - cd .. - - # co - dotest import-97 "${testcvs} -q co first-dir" \ -"U first-dir/imported-f1 -U first-dir/imported-f2 -U first-dir/imported-f3 -U first-dir/imported-f4" - - cd first-dir - - for i in 1 2 3 4 ; do - dotest import-98-$i "test -f imported-f$i" '' - done - dotest_fail import-98.5 "test -d RCS" '' - - # remove - rm imported-f1 - dotest import-99 "${testcvs} rm imported-f1" \ -"${PROG}"' remove: scheduling `imported-f1'\'' for removal -'"${PROG}"' remove: use .'"${PROG}"' commit. to remove this file permanently' - - # change - echo local-change >> imported-f2 - - # commit - dotest import-100 "${testcvs} ci -m local-changes" \ -"${PROG} [a-z]*: Examining . -Removing imported-f1; -${CVSROOT_DIRNAME}/first-dir/imported-f1,v <-- imported-f1 -new revision: delete; previous revision: 1\.1\.1\.1 -done -Checking in imported-f2; -${CVSROOT_DIRNAME}/first-dir/imported-f2,v <-- imported-f2 -new revision: 1\.2; previous revision: 1\.1 -done" - - # log - dotest import-101 "${testcvs} log imported-f1" \ -" -RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/imported-f1,v -Working file: imported-f1 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - junk-1_0: 1\.1\.1\.1 - vendor-branch: 1\.1\.1 -keyword substitution: kv -total revisions: 3; selected revisions: 3 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: dead; lines: ${PLUS}0 -0 -local-changes ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -branches: 1\.1\.1; -Initial revision ----------------------------- -revision 1\.1\.1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}0 -0 -first-import -=============================================================================" - - # update into the vendor branch. - dotest import-102 "$testcvs update -rvendor-branch" \ -"$PROG update: Updating . -U imported-f1 -[UP] imported-f2 -[UP] imported-f3 -[UP] imported-f4" - - # remove file4 on the vendor branch - rm imported-f4 - dotest import-103 "${testcvs} rm imported-f4" \ -"${PROG}"' remove: scheduling `imported-f4'\'' for removal -'"${PROG}"' remove: use .'"${PROG}"' commit. to remove this file permanently' - - # commit - dotest import-104 \ -"${testcvs} ci -m vendor-removed imported-f4" \ -"Removing imported-f4; -${CVSROOT_DIRNAME}/first-dir/imported-f4,v <-- imported-f4 -new revision: delete; previous revision: 1\.1\.1\.1 -done" - - # update to main line - dotest import-105 "$testcvs -q update -A" \ -"$PROG update: imported-f1 is no longer in the repository -[UP] imported-f2 -[UP] imported-f3" - - # second import - file4 deliberately unchanged - cd ../import-dir - for i in 1 2 3 ; do - echo rev 2 of file $i >> imported-f"$i" - done - cp imported-f2 ../imported-f2-orig.tmp - - dotest_sort import-106 \ -"${testcvs} import -m second-import first-dir vendor-branch junk-2_0" \ -" - - - ${PROG} checkout -j<prev_rel_tag> -jjunk-2_0 first-dir -2 conflicts created by this import. -C first-dir/imported-f1 -C first-dir/imported-f2 -I first-dir/RCS -U first-dir/imported-f3 -U first-dir/imported-f4 -Use the following command to help the merge:" - - dotest import-106.5 "cmp ../imported-f2-orig.tmp imported-f2" \ -'' - - cd .. - - rm imported-f2-orig.tmp - - # co - dotest import-107 "${testcvs} co first-dir" \ -"${PROG} checkout: Updating first-dir -[UP] first-dir/imported-f3 -[UP] first-dir/imported-f4" - - cd first-dir - - dotest_fail import-108 "test -f imported-f1" '' - - for i in 2 3 ; do - dotest import-109-$i "test -f imported-f$i" '' - done - - # check vendor branch for file4 - dotest import-110 "$testcvs -q update -rvendor-branch" \ -'U imported-f1 -[UP] imported-f2 -[UP] imported-f3 -[UP] imported-f4' - - dotest import-111 "test -f imported-f4" '' - - # update to main line - dotest import-112 "$testcvs -q update -A" \ -"$PROG update: imported-f1 is no longer in the repository -[UP] imported-f2 -[UP] imported-f3 -[UP] imported-f4" - - cd .. - - dotest import-113 \ -"${testcvs} -q co -jjunk-1_0 -jjunk-2_0 first-dir" \ -"${PROG} checkout: file first-dir/imported-f1 does not exist, but is present in revision junk-2_0 -RCS file: ${CVSROOT_DIRNAME}/first-dir/imported-f2,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.2 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into imported-f2 -rcsmerge: warning: conflicts during merge -first-dir/imported-f3 already contains the differences between 1\.1\.1\.1 and 1\.1\.1\.2 -first-dir/imported-f4 already contains the differences between 1\.1\.1\.1 and 1\.1\.1\.3" - - cd first-dir - - dotest_fail import-114 "test -f imported-f1" '' - - for i in 2 3 ; do - dotest import-115-$i "test -f imported-f$i" '' - done - - dotest import-116 'cat imported-f2' \ -'imported file2 -[<]<<<<<< imported-f2 -import should not expand \$''Id: imported-f2,v 1\.2 [0-9/]* [0-9:]* '"${username}"' Exp \$ -local-change -[=]====== -import should not expand \$''Id: imported-f2,v 1\.1\.1\.2 [0-9/]* [0-9:]* '"${username}"' Exp \$ -rev 2 of file 2 -[>]>>>>>> 1\.1\.1\.2' - - cd .. - rm -r first-dir - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -r import-dir - ;; - - importb) - # More cvs import tests, especially -b option. - - # OK, first we get some sources from the NetMunger project, and - # import them into the 1.1.1 vendor branch. - mkdir imp-dir - cd imp-dir - echo 'OpenMunger sources' >file1 - echo 'OpenMunger sources' >file2 - dotest_sort importb-1 \ -"${testcvs} import -m add first-dir openmunger openmunger-1_0" \ -" - -N first-dir/file1 -N first-dir/file2 -No conflicts created by this import" - cd .. - rm -r imp-dir - - # Now we put the sources we get from FreeMunger into 1.1.3 - mkdir imp-dir - cd imp-dir - echo 'FreeMunger sources' >file1 - echo 'FreeMunger sources' >file2 - # Not completely sure how the conflict detection is supposed to - # be working here (haven't really thought about it). - # We use an explicit -d option to test that it is reflected - # in the suggested checkout. - dotest_sort importb-2 \ -"${testcvs} -d ${CVSROOT} import -m add -b 1.1.3 first-dir freemunger freemunger-1_0" \ -" - - - ${PROG} -d ${CVSROOT} checkout -j<prev_rel_tag> -jfreemunger-1_0 first-dir -2 conflicts created by this import. -C first-dir/file1 -C first-dir/file2 -Use the following command to help the merge:" - cd .. - rm -r imp-dir - - # Now a test of main branch import (into second-dir, not first-dir). - mkdir imp-dir - cd imp-dir - echo 'my own stuff' >mine1.c - echo 'my own stuff' >mine2.c - dotest_fail importb-3 \ -"${testcvs} import -m add -b 1 second-dir dummy really_dumb_y" \ -"$PROG \[import aborted\]: Only numeric branch specifications with two dots are -supported by import, not \`1'\. For example: \`1\.1\.1'\." - : when we implement main-branch import, should be \ -"N second-dir/mine1\.c -N second-dir/mine2\.c - -No conflicts created by this import" - cd .. - rm -r imp-dir - - mkdir 1 - cd 1 - # when we implement main branch import, will want to - # add "second-dir" here. - dotest importb-4 "${testcvs} -q co first-dir" \ -"U first-dir/file1 -U first-dir/file2" - cd first-dir - dotest importb-5 "${testcvs} -q log file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: 1\.1\.1 -locks: strict -access list: -symbolic names: - freemunger-1_0: 1\.1\.3\.1 - freemunger: 1\.1\.3 - openmunger-1_0: 1\.1\.1\.1 - openmunger: 1\.1\.1 -keyword substitution: kv -total revisions: 3; selected revisions: 3 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -branches: 1\.1\.1; 1\.1\.3; -Initial revision ----------------------------- -revision 1\.1\.3\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -1 -add ----------------------------- -revision 1\.1\.1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}0 -0 -add -=============================================================================" - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir ${CVSROOT_DIRNAME}/second-dir - ;; - - importc) - # Test importing a bunch o' files in a bunch o' directories. - # Also the -d option. - mkdir 1; cd 1 - mkdir adir bdir cdir - mkdir adir/sub1 adir/sub2 - mkdir adir/sub1/ssdir - mkdir bdir/subdir - touch adir/sub1/file1 adir/sub2/file2 adir/sub1/ssdir/ssfile - touch -t 197107040343 bdir/subdir/file1 - touch -t 203412251801 cdir/cfile - dotest_sort importc-1 \ -"${testcvs} import -d -m import-it first-dir vendor release" \ -" - -N first-dir/adir/sub1/file1 -N first-dir/adir/sub1/ssdir/ssfile -N first-dir/adir/sub2/file2 -N first-dir/bdir/subdir/file1 -N first-dir/cdir/cfile -No conflicts created by this import -${PROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir -${PROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir/sub1 -${PROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir/sub1/ssdir -${PROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir/sub2 -${PROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/bdir -${PROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/bdir/subdir -${PROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/cdir" - cd .. - mkdir 2; cd 2 - dotest importc-2 "${testcvs} -q co first-dir" \ -"U first-dir/adir/sub1/file1 -U first-dir/adir/sub1/ssdir/ssfile -U first-dir/adir/sub2/file2 -U first-dir/bdir/subdir/file1 -U first-dir/cdir/cfile" - cd first-dir - dotest importc-3 "${testcvs} update adir/sub1" \ -"${PROG} update: Updating adir/sub1 -${PROG} update: Updating adir/sub1/ssdir" - dotest importc-4 "${testcvs} update adir/sub1 bdir/subdir" \ -"${PROG} update: Updating adir/sub1 -${PROG} update: Updating adir/sub1/ssdir -${PROG} update: Updating bdir/subdir" - - echo modify >>cdir/cfile - dotest importc-5 \ -"${testcvs} -q rtag -b -r release wip_test first-dir" "" - dotest importc-6 "$testcvs -q update -r wip_test" \ -'U adir/sub1/file1 -U adir/sub1/ssdir/ssfile -U adir/sub2/file2 -U bdir/subdir/file1 -M cdir/cfile' - - # This used to fail in local mode - dotest importc-7 "${testcvs} -q ci -m modify -r wip_test" \ -"Checking in cdir/cfile; -${CVSROOT_DIRNAME}/first-dir/cdir/cfile,v <-- cfile -new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 -done" - - # TODO: should also be testing "import -d" when we update - # an existing file. - dotest importc-8 "${testcvs} -q log cdir/cfile" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/cdir/cfile,v -Working file: cdir/cfile -head: 1\.1 -branch: 1\.1\.1 -locks: strict -access list: -symbolic names: - wip_test: 1\.1\.1\.1\.0\.2 - release: 1\.1\.1\.1 - vendor: 1\.1\.1 -keyword substitution: kv -total revisions: 3; selected revisions: 3 -description: ----------------------------- -revision 1\.1 -date: 2034/12/2[4-6] [0-9][0-9]:01:[0-9][0-9]; author: ${username}; state: Exp; -branches: 1\.1\.1; -Initial revision ----------------------------- -revision 1\.1\.1\.1 -date: 2034/12/2[4-6] [0-9][0-9]:01:[0-9][0-9]; author: ${username}; state: Exp; lines: ${PLUS}0 -0 -branches: 1\.1\.1\.1\.2; -import-it ----------------------------- -revision 1\.1\.1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -modify -=============================================================================" - - dotest importc-9 "${testcvs} -q log bdir/subdir/file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/bdir/subdir/file1,v -Working file: bdir/subdir/file1 -head: 1\.1 -branch: 1\.1\.1 -locks: strict -access list: -symbolic names: - wip_test: 1\.1\.1\.1\.0\.2 - release: 1\.1\.1\.1 - vendor: 1\.1\.1 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.1 -date: 1971/07/0[3-5] [0-9][0-9]:43:[0-9][0-9]; author: ${username}; state: Exp; -branches: 1\.1\.1; -Initial revision ----------------------------- -revision 1\.1\.1\.1 -date: 1971/07/0[3-5] [0-9][0-9]:43:[0-9][0-9]; author: ${username}; state: Exp; lines: ${PLUS}0 -0 -import-it -=============================================================================" - cd .. - - # Now tests of absolute pathnames and .. as repository directory. - cd ../1 - dotest_fail importc-10 \ -"${testcvs} import -m imp ../other vendor release2" \ -"${PROG} \[[a-z]* aborted\]: directory \.\./other not relative within the repository" - dotest_fail importc-11 \ -"${testcvs} import -m imp ${TESTDIR}/other vendor release3" \ -"${PROG} \[[a-z]* aborted\]: directory ${TESTDIR}/other not relative within the repository" - dotest_fail importc-12 "test -d ${TESTDIR}/other" "" - cd .. - - rm -r 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - import-CVS) - mkdir import-CVS - cd import-CVS - touch file1 file2 file3 - dotest_fail import-CVS-1 "$testcvs import -mimport CVS vtag rtag" \ -"$PROG import: The word \`CVS' is reserved by CVS and may not be used -$PROG \[import aborted\]: as a directory in a path or as a file name\." - dotest_fail import-CVS-1b \ -"$testcvs import -mimport CVS-/CVS vtag rtag" \ -"$PROG import: The word \`CVS' is reserved by CVS and may not be used -$PROG \[import aborted\]: as a directory in a path or as a file name\." - mkdir sdir - mkdir sdir/CVS - touch CVS sdir/CVS/file4 sdir/CVS/file5 sdir/file6 sdir/file7 - # Calling the imported directory import-CVS is dual purpose in the - # following test. It makes sure the path test which matched above - # wasn't too strict. - dotest_sort import-CVS-2 \ -"$testcvs import -I! -mimport import-CVS vtag rtag" \ -" - -I import-CVS/CVS -I import-CVS/sdir/CVS -N import-CVS/file1 -N import-CVS/file2 -N import-CVS/file3 -N import-CVS/sdir/file6 -N import-CVS/sdir/file7 -No conflicts created by this import -$PROG import: Importing $CVSROOT_DIRNAME/import-CVS/sdir" - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd .. - rm -r import-CVS - rm -rf $CVSROOT_DIRNAME/import-CVS - ;; - - - - import-quirks) - # Short tests of quirky import behavior. - # - # For a list of other import tests with short descriptions, see the - # comment header of the "import" test. - mkdir import-quirks - cd import-quirks - touch file1 file2 file3 - - # CVS prior to 1.11.18 and 1.12.10 used to happily import to - # "branch 1.1", creating RCS archives with revisions like, - # "1.1..1". That double-dot is *not* a typo. - dotest_fail import-quirks-1 \ -"$testcvs import -b1.1. -mbad-bad-bad import-quirks VB RT" \ -"$PROG \[import aborted\]: Only numeric branch specifications with two dots are -supported by import, not \`1\.1\.'\. For example: \`1\.1\.1'\." - - dotest_fail import-quirks-2 \ -"$testcvs import -b1.1.1.. -mbad-bad-bad import-quirks VB RT" \ -"$PROG \[import aborted\]: Only numeric branch specifications with two dots are -supported by import, not \`1\.1\.1\.\.'\. For example: \`1\.1\.1'\." - - # Try a few odd numbers. This is hardly comprehensive. - dotest_sort import-quirks-2 \ -"$testcvs import -b10.10.101 -mthis-ones-ok import-quirks-2 VB RT" \ -" - -N import-quirks-2/file1 -N import-quirks-2/file2 -N import-quirks-2/file3 -No conflicts created by this import" - - dotest_sort import-quirks-3 \ -"$testcvs import -b2345678901.2345678901.2345678901 -mthis-ones-ok import-quirks-3 VB RT" \ -" - -N import-quirks-3/file1 -N import-quirks-3/file2 -N import-quirks-3/file3 -No conflicts created by this import" - - dotest_sort import-quirks-4 \ -"$testcvs import -b1.1.2 -mthis-ones-ok import-quirks-4 VB RT" \ -" - -N import-quirks-4/file1 -N import-quirks-4/file2 -N import-quirks-4/file3 -No conflicts created by this import" - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd .. - rm -r import-quirks - rm -rf $CVSROOT_DIRNAME/import-quirks-2 \ - $CVSROOT_DIRNAME/import-quirks-3 \ - $CVSROOT_DIRNAME/import-quirks-4 - ;; - - - - import-after-initial) - # Properly handle the case in which the first version of a - # file is created by a regular cvs add and commit, and there - # is a subsequent cvs import of the same file. cvs update with - # a date tag must resort to searching the vendor branch only if - # the initial version of the file was created at the same time - # as the initial version on the vendor branch. - - mkdir 1; cd 1 - module=x - - echo > unused-file - - # Create the module. - dotest import-after-initial-1 \ - "$testcvs -Q import -m. $module X Y" '' - - file=m - # Check it out and add a file. - dotest import-after-initial-2 "$testcvs -Q co $module" '' - cd $module - echo original > $file - dotest import-after-initial-3 "${testcvs} -Q add $file" "" - dotest import-after-initial-4 "${testcvs} -Q ci -m. $file" \ -"RCS file: ${CVSROOT_DIRNAME}/$module/$file,v -done -Checking in $file; -${CVSROOT_DIRNAME}/$module/$file,v <-- $file -initial revision: 1\.1 -done" - - # Delay a little so the following import isn't done in the same - # second as the preceding commit. - sleep 2 - - # Do the first import of $file *after* $file already has an - # initial version. - mkdir sub - cd sub - echo newer-via-import > $file - dotest import-after-initial-5 \ - "$testcvs -Q import -m. $module X Y2" '' - cd .. - - # Sleep a second so we're sure to be after the second of the import. - sleep 1 - - dotest import-after-initial-6 \ - "$testcvs -Q update -p -D now $file" 'original' - - cd ../.. - rm -rf 1 - rm -rf ${CVSROOT_DIRNAME}/$module - ;; - - branch-after-import) - # Test branching after an import via both cvs tag -b and - # cvs add to verify that the HEAD remains at 1.1.1.1 - # This was a FreeBSD bug documented at the URL: - # http://www.freebsd.org/cgi/query-pr.cgi?pr=4033 - - mkdir branch-after-import - cd branch-after-import - - # OK, first we get some sources from the NetMunger project, - # and import them into the 1.1.1 vendor branch. - mkdir imp-dir - cd imp-dir - echo 'OpenMunger sources' >file1 - echo 'OpenMunger sources' >file2 - dotest_sort branch-after-import-1 \ -"${testcvs} import -m add first-dir openmunger openmunger-1_0" \ -' - -N first-dir/file1 -N first-dir/file2 -No conflicts created by this import' - cd .. - - # Next checkout the new module - dotest branch-after-import-2 \ -"${testcvs} -q co first-dir" \ -'U first-dir/file1 -U first-dir/file2' - cd first-dir - # Branch tag the file1 and cvs add file2, - # the branch should remain the same in both cases - # such that a new import will not require a conflict - # resolution. - dotest branch-after-import-3 \ -"${testcvs} tag -b TESTTOTRON file1" \ -'T file1' - dotest branch-after-import-4 \ -"$testcvs -q update -r TESTTOTRON" \ -"[UP] file1 -$PROG update: file2 is no longer in the repository" - - cp ../imp-dir/file2 . - dotest branch-after-import-5 \ -"${testcvs} add file2" \ -"${PROG} add: scheduling file .file2. for addition on branch .TESTTOTRON. -${PROG} add: use .${PROG} commit. to add this file permanently" - - dotest branch-after-import-6 \ -"${testcvs} commit -m cvs-add file2" \ -"Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.1\.1\.1\.2\.2; previous revision: 1\.1\.1\.1\.2\.1 -done" - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd ../.. - rm -r branch-after-import - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - join) - # Test doing joins which involve adding and removing files. - # Variety of scenarios (see list below), in the context of: - # * merge changes from T1 to T2 into the main line - # * merge changes from branch 'branch' into the main line - # * merge changes from branch 'branch' into branch 'br2'. - # See also binfile2, which does similar things with binary files. - # See also join2, which tests joining (and update -A) on only - # a single file, rather than a directory. - # See also rmadd2, which tests -j cases not involving branches - # (e.g. undoing a commit) - # See also join3, which tests some cases involving the greatest - # common ancestor. Here is a list of tests according to branch - # topology: - # - # --->bp---->trunk too many to mention - # \----->branch - # - # /----->branch1 - # --->bp---->trunk multibranch, multibranch2 - # \----->branch2 - # - # --->bp1----->bp2---->trunk join3 - # \->br1 \->br2 - # - # --->bp1----->trunk - # \----bp2---->branch branches - # \------>branch-of-branch - - # We check merging changes from T1 to T2 into the main line. - # Here are the interesting cases I can think of: - # 1) File added between T1 and T2, not on main line. - # File should be marked for addition. - # 2) File added between T1 and T2, also added on main line. - # Conflict. - # 3) File removed between T1 and T2, unchanged on main line. - # File should be marked for removal. - # 4) File removed between T1 and T2, modified on main line. - # If mod checked in, file should be marked for removal. - # If mod still in working directory, conflict. - # 5) File removed between T1 and T2, was never on main line. - # Nothing should happen. - # 6) File removed between T1 and T2, also removed on main line. - # Nothing should happen. - # 7) File not added between T1 and T2, added on main line. - # Nothing should happen. - # 8) File not modified between T1 and T2, removed on main line. - # Nothing should happen. - # 9) File modified between T1 and T2, removed on main line. - # Conflict. - # 10) File was never on branch, removed on main line. - # Nothing should happen. - - # We also check merging changes from a branch into the main - # line. Here are the interesting cases: - # 1) File added on branch, not on main line. - # File should be marked for addition. - # 2) File added on branch, also added on main line. - # Conflict. - # 3) File removed on branch, unchanged on main line. - # File should be marked for removal. - # 4) File removed on branch, modified on main line. - # Conflict. - # 5) File removed on branch, was never on main line. - # Nothing should happen. - # 6) File removed on branch, also removed on main line. - # Nothing should happen. - # 7) File added on main line, not added on branch. - # Nothing should happen. - # 8) File removed on main line, not modified on branch. - # Nothing should happen. - # 9) File modified on branch, removed on main line. - # Conflict. - # 10) File was never on branch, removed on main line. - # Nothing should happen. - - # In the tests below, fileN represents case N in the above - # lists. - - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir 1 - cd 1 - dotest join-1 "${testcvs} -q co first-dir" '' - - cd first-dir - - # Add two files. - echo 'first revision of file3' > file3 - echo 'first revision of file4' > file4 - echo 'first revision of file6' > file6 - echo 'first revision of file8' > file8 - echo 'first revision of file9' > file9 - dotest join-2 "${testcvs} add file3 file4 file6 file8 file9" \ -"${PROG}"' add: scheduling file `file3'\'' for addition -'"${PROG}"' add: scheduling file `file4'\'' for addition -'"${PROG}"' add: scheduling file `file6'\'' for addition -'"${PROG}"' add: scheduling file `file8'\'' for addition -'"${PROG}"' add: scheduling file `file9'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add these files permanently' - - dotest join-3 "${testcvs} -q commit -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file3,v -done -Checking in file3; -${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file6,v -done -Checking in file6; -${CVSROOT_DIRNAME}/first-dir/file6,v <-- file6 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file8,v -done -Checking in file8; -${CVSROOT_DIRNAME}/first-dir/file8,v <-- file8 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file9,v -done -Checking in file9; -${CVSROOT_DIRNAME}/first-dir/file9,v <-- file9 -initial revision: 1\.1 -done" - - # Make a branch. - dotest join-4 "${testcvs} -q tag -b branch ." \ -'T file3 -T file4 -T file6 -T file8 -T file9' - - # Add file2, file7, and file10, modify file4, and remove - # file6, file8, and file9. - echo 'first revision of file2' > file2 - echo 'second revision of file4' > file4 - echo 'first revision of file7' > file7 - rm file6 file8 file9 - echo 'first revision of file10' > file10 - dotest join-5 "${testcvs} add file2 file7 file10" \ -"${PROG}"' add: scheduling file `file2'\'' for addition -'"${PROG}"' add: scheduling file `file7'\'' for addition -'"${PROG}"' add: scheduling file `file10'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add these files permanently' - dotest join-6 "${testcvs} rm file6 file8 file9" \ -"${PROG}"' remove: scheduling `file6'\'' for removal -'"${PROG}"' remove: scheduling `file8'\'' for removal -'"${PROG}"' remove: scheduling `file9'\'' for removal -'"${PROG}"' remove: use .'"${PROG}"' commit. to remove these files permanently' - dotest join-7 "${testcvs} -q ci -mx ." \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file10,v -done -Checking in file10; -${CVSROOT_DIRNAME}/first-dir/file10,v <-- file10 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: 1\.2; previous revision: 1\.1 -done -Removing file6; -${CVSROOT_DIRNAME}/first-dir/file6,v <-- file6 -new revision: delete; previous revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file7,v -done -Checking in file7; -${CVSROOT_DIRNAME}/first-dir/file7,v <-- file7 -initial revision: 1\.1 -done -Removing file8; -${CVSROOT_DIRNAME}/first-dir/file8,v <-- file8 -new revision: delete; previous revision: 1\.1 -done -Removing file9; -${CVSROOT_DIRNAME}/first-dir/file9,v <-- file9 -new revision: delete; previous revision: 1\.1 -done" - - # Remove file10 - dotest join-7a "${testcvs} rm -f file10" \ -"${PROG}"' remove: scheduling `file10'\'' for removal -'"${PROG}"' remove: use .'"${PROG}"' commit. to remove this file permanently' - dotest join-7b "${testcvs} -q ci -mx ." \ -"Removing file10; -${CVSROOT_DIRNAME}/first-dir/file10,v <-- file10 -new revision: delete; previous revision: 1\.1 -done" - - # Check out the branch. - cd ../.. - mkdir 2 - cd 2 - dotest join-8 "${testcvs} -q co -r branch first-dir" \ -'U first-dir/file3 -U first-dir/file4 -U first-dir/file6 -U first-dir/file8 -U first-dir/file9' - - cd first-dir - - # Modify the files on the branch, so that T1 is not an - # ancestor of the main line, and add file5 - echo 'first branch revision of file3' > file3 - echo 'first branch revision of file4' > file4 - echo 'first branch revision of file5' > file5 - echo 'first branch revision of file6' > file6 - echo 'first branch revision of file9' > file9 - dotest join-9 "${testcvs} add file5" \ -"${PROG}"' add: scheduling file `file5'\'' for addition on branch `branch'\'' -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest join-10 "${testcvs} -q ci -mx ." \ -"Checking in file3; -${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file5,v -done -Checking in file5; -${CVSROOT_DIRNAME}/first-dir/Attic/file5,v <-- file5 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in file6; -${CVSROOT_DIRNAME}/first-dir/Attic/file6,v <-- file6 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in file9; -${CVSROOT_DIRNAME}/first-dir/Attic/file9,v <-- file9 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - # Tag the current revisions on the branch. - dotest join-11 "${testcvs} -q tag T1 ." \ -'T file3 -T file4 -T file5 -T file6 -T file8 -T file9' - - # Add file1 and file2, modify file9, and remove the other files. - echo 'first branch revision of file1' > file1 - echo 'first branch revision of file2' > file2 - echo 'second branch revision of file9' > file9 - rm file3 file4 file5 file6 - dotest join-12 "${testcvs} add file1 file2" \ -"${PROG}"' add: scheduling file `file1'\'' for addition on branch `branch'\'' -'"${PROG}"' add: scheduling file `file2'\'' for addition on branch `branch'\'' -'"${PROG}"' add: use .'"${PROG}"' commit. to add these files permanently' - dotest join-13 "${testcvs} rm file3 file4 file5 file6" \ -"${PROG}"' remove: scheduling `file3'\'' for removal -'"${PROG}"' remove: scheduling `file4'\'' for removal -'"${PROG}"' remove: scheduling `file5'\'' for removal -'"${PROG}"' remove: scheduling `file6'\'' for removal -'"${PROG}"' remove: use .'"${PROG}"' commit. to remove these files permanently' - dotest join-14 "${testcvs} -q ci -mx ." \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/Attic/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 -done -Removing file3; -${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3 -new revision: delete; previous revision: 1\.1\.2\.1 -done -Removing file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: delete; previous revision: 1\.1\.2\.1 -done -Removing file5; -${CVSROOT_DIRNAME}/first-dir/Attic/file5,v <-- file5 -new revision: delete; previous revision: 1\.1\.2\.1 -done -Removing file6; -${CVSROOT_DIRNAME}/first-dir/Attic/file6,v <-- file6 -new revision: delete; previous revision: 1\.1\.2\.1 -done -Checking in file9; -${CVSROOT_DIRNAME}/first-dir/Attic/file9,v <-- file9 -new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 -done" - - # Tag the current revisions on the branch. - dotest join-15 "${testcvs} -q tag T2 ." \ -'T file1 -T file2 -T file8 -T file9' - - # Do a checkout with a merge. - cd ../.. - mkdir 3 - cd 3 - dotest join-16 "$testcvs -q co -jT1 -jT2 first-dir" \ -"U first-dir/file1 -U first-dir/file2 -$PROG checkout: file first-dir/file2 exists, but has been added in revision T2 -U first-dir/file3 -$PROG checkout: scheduling first-dir/file3 for removal -U first-dir/file4 -$PROG checkout: file first-dir/file4 has been removed in revision T2, but the destination is incompatibly modified -C first-dir/file4 -U first-dir/file7 -$PROG checkout: file first-dir/file9 does not exist, but is present in revision T2" - - # Verify that the right changes have been scheduled. - cd first-dir - dotest_fail join-17 "$testcvs -q update" \ -'A file1 -R file3 -C file4' - - # Modify file4 locally, and do an update with a merge. - cd ../../1/first-dir - echo 'third revision of file4' > file4 - dotest join-18 "$testcvs -q update -jT1 -jT2 ." \ -"U file1 -$PROG update: file file2 exists, but has been added in revision T2 -$PROG update: scheduling file3 for removal -M file4 -$PROG update: file file4 has been removed in revision T2, but the destination is incompatibly modified -C file4 -$PROG update: file file9 does not exist, but is present in revision T2" - - # Verify that the right changes have been scheduled. - dotest_fail join-19 "$testcvs -q update" \ -'A file1 -R file3 -C file4' - - # Do a checkout with a merge from a single revision. - - # FIXME: CVS currently gets this wrong. file2 has been - # added on both the branch and the main line, and so should - # be regarded as a conflict. However, given the way that - # CVS sets up the RCS file, there is no way to distinguish - # this case from the case of file2 having existed before the - # branch was made. This could be fixed by reserving - # a revision somewhere, perhaps 1.1, as an always dead - # revision which can be used as the source for files added - # on branches. - cd ../../3 - rm -r first-dir - dotest join-20 "$testcvs -q co -jbranch first-dir" \ -"U first-dir/file1 -U first-dir/file2 -RCS file: $CVSROOT_DIRNAME/first-dir/file2,v -retrieving revision 1\.1 -retrieving revision 1\.1\.2\.2 -Merging differences between 1\.1 and 1\.1\.2\.2 into file2 -U first-dir/file3 -$PROG checkout: scheduling first-dir/file3 for removal -U first-dir/file4 -$PROG checkout: file first-dir/file4 has been removed in revision branch, but the destination is incompatibly modified -C first-dir/file4 -U first-dir/file7 -$PROG checkout: file first-dir/file9 does not exist, but is present in revision branch" - - # Verify that the right changes have been scheduled. - # The M file2 line is a bug; see above join-20. - cd first-dir - dotest_fail join-21 "$testcvs -q update" \ -'A file1 -M file2 -R file3 -C file4' - - # Checkout the main line again. - cd ../../1 - rm -r first-dir - dotest join-22 "${testcvs} -q co first-dir" \ -'U first-dir/file2 -U first-dir/file3 -U first-dir/file4 -U first-dir/file7' - - # Modify file4 locally, and do an update with a merge from a - # single revision. - # The file2 handling is a bug; see above join-20. - cd first-dir - echo 'third revision of file4' > file4 - dotest join-23 "$testcvs -q update -jbranch ." \ -"U file1 -RCS file: $CVSROOT_DIRNAME/first-dir/file2,v -retrieving revision 1\.1 -retrieving revision 1\.1\.2\.2 -Merging differences between 1\.1 and 1\.1\.2\.2 into file2 -$PROG update: scheduling file3 for removal -M file4 -$PROG update: file file4 has been removed in revision branch, but the destination is incompatibly modified -C file4 -$PROG update: file file9 does not exist, but is present in revision branch" - - # Verify that the right changes have been scheduled. - # The M file2 line is a bug; see above join-20 - dotest_fail join-24 "$testcvs -q update" \ -'A file1 -M file2 -R file3 -C file4' - - cd .. - - # Checkout the main line again and make a new branch which we - # merge to. - rm -r first-dir - dotest join-25 "${testcvs} -q co first-dir" \ -'U first-dir/file2 -U first-dir/file3 -U first-dir/file4 -U first-dir/file7' - cd first-dir - dotest join-26 "${testcvs} -q tag -b br2" \ -"T file2 -T file3 -T file4 -T file7" - dotest join-27 "$testcvs -q update -r br2" \ -'[UP] file2 -[UP] file3 -[UP] file4 -[UP] file7' - # The handling of file8 and file9 here look fishy to me. I don't - # see why it should be different from the case where we merge to - # the trunk (e.g. join-23). - dotest join-28 "$testcvs -q update -j branch" \ -"U file1 -RCS file: $CVSROOT_DIRNAME/first-dir/file2,v -retrieving revision 1\.1 -retrieving revision 1\.1\.2\.2 -Merging differences between 1\.1 and 1\.1\.2\.2 into file2 -$PROG update: scheduling file3 for removal -$PROG update: file file4 has been removed in revision branch, but the destination is incompatibly modified -C file4 -U file8 -U file9" - # Verify that the right changes have been scheduled. - dotest_fail join-29 "$testcvs -q update" \ -"A file1 -M file2 -R file3 -C file4 -A file8 -A file9" - - # Checkout the mainline again to try updating and merging between two - # branches in the same step - # this seems a likely scenario - the user finishes up on branch and - # updates to br2 and merges in the same step - and there was a bug - # once that if the file was removed in the update then it wouldn't be - # readded in the merge - cd .. - rm -rf first-dir - dotest join-twobranch-1 "${testcvs} -q co -rbranch first-dir" \ -'U first-dir/file1 -U first-dir/file2 -U first-dir/file8 -U first-dir/file9' - cd first-dir - dotest join-twobranch-2 "$testcvs -q update -rbr2 -jbranch" \ -"$PROG update: file1 is no longer in the repository -U file1 -U file2 -RCS file: $CVSROOT_DIRNAME/first-dir/file2,v -retrieving revision 1\.1 -retrieving revision 1\.1\.2\.2 -Merging differences between 1\.1 and 1\.1\.2\.2 into file2 -U file3 -$PROG update: scheduling file3 for removal -U file4 -$PROG update: file file4 has been removed in revision branch, but the destination is incompatibly modified -C file4 -U file7 -$PROG update: file8 is no longer in the repository -U file8 -$PROG update: file9 is no longer in the repository -U file9" - # Verify that the right changes have been scheduled. - dotest_fail join-twobranch-3 "$testcvs -q update" \ -"A file1 -M file2 -R file3 -C file4 -A file8 -A file9" - - # 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; -${CVSROOT_DIRNAME}/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} update: 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: ${CVSROOT_DIRNAME}/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 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - join2) - # More joining tests. - - # First the usual setup; create a directory first-dir, a file - # first-dir/file1, and a branch br1. - mkdir 1; cd 1 - dotest join2-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest join2-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - echo 'initial contents of file1' >file1 - dotest join2-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest join2-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - dotest join2-5 "${testcvs} -q tag -b br1" "T file1" - dotest join2-6 "$testcvs -q update -r br1" '[UP] file1' - echo 'modify on branch' >>file1 - touch bradd - dotest join2-6a "${testcvs} add bradd" \ -"${PROG} add: scheduling file .bradd. for addition on branch .br1. -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest join2-7 "${testcvs} -q ci -m modify" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/bradd,v -done -Checking in bradd; -${CVSROOT_DIRNAME}/first-dir/Attic/bradd,v <-- bradd -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - # Here is the unusual/pathological part. We switch back to - # the trunk *for file1 only*, not for the whole directory. - dotest join2-8 "${testcvs} -q update -A file1" '[UP] file1' - dotest join2-9 "${testcvs} -q status file1" \ -"=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest join2-10 "cat CVS/Tag" "Tbr1" - - dotest join2-11 "${testcvs} -q update -j br1 file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.1 -retrieving revision 1\.1\.2\.1 -Merging differences between 1\.1 and 1\.1\.2\.1 into file1" - dotest join2-12 "cat file1" "initial contents of file1 -modify on branch" - # We should have no sticky tag on file1 - dotest join2-13 "${testcvs} -q status file1" \ -"=================================================================== -File: file1 Status: Locally Modified - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest join2-14 "cat CVS/Tag" "Tbr1" - # And the checkin should go to the trunk - dotest join2-15 "${testcvs} -q ci -m modify file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - - # OK, the above is all well and good and has worked for some - # time. Now try the case where the file had been added on - # the branch. - dotest join2-16 "${testcvs} -q update -r br1" "[UP] file1" - # The workaround is to update the whole directory. - # The non-circumvented version won't work. The reason is that - # update removes the entry from CVS/Entries, so of course we get - # the tag from CVS/Tag and not Entries. I suppose maybe - # we could invent some new format in Entries which would handle - # this, but doing so, and handling it properly throughout - # CVS, would be a lot of work and I'm not sure this case justifies - # it. - dotest join2-17-circumvent "${testcvs} -q update -A" \ -"${PROG} update: bradd is no longer in the repository -[UP] file1" -: dotest join2-17 "${testcvs} -q update -A bradd" \ -"${PROG} update: warning: bradd is not (any longer) pertinent" - dotest join2-18 "${testcvs} -q update -j br1 bradd" "U bradd" - dotest join2-19 "${testcvs} -q status bradd" \ -"=================================================================== -File: bradd Status: Locally Added - - Working revision: New file! - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/Attic/bradd,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest join2-20 "${testcvs} -q ci -m modify bradd" \ -"Checking in bradd; -${CVSROOT_DIRNAME}/first-dir/bradd,v <-- bradd -new revision: 1\.2; previous revision: 1\.1 -done" - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - join3) - # See "join" for a list of other joining/branching tests. - # First the usual setup; create a directory first-dir, a file - # first-dir/file1, and a branch br1. - mkdir 1; cd 1 - dotest join3-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest join3-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - echo 'initial contents of file1' >file1 - dotest join3-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest join3-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - dotest join3-5 "${testcvs} -q tag -b br1" "T file1" - dotest join3-6 "$testcvs -q update -r br1" '[UP] file1' - echo 'br1:line1' >>file1 - dotest join3-7 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - # Now back to the trunk for: - # another revision and another branch for file1. - # add file2, which will exist on trunk and br2 but not br1. - dotest join3-8 "${testcvs} -q update -A" "[UP] file1" - echo 'trunk:line1' > file2 - dotest join3-8a "${testcvs} add file2" \ -"${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - echo 'trunk:line1' >>file1 - dotest join3-9 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - dotest join3-10 "${testcvs} -q tag -b br2" "T file1 -T file2" - - # Before we actually have any revision on br2, let's try a join - dotest join3-11 "${testcvs} -q update -r br1" "[UP] file1 -${PROG} update: file2 is no longer in the repository" - dotest join3-12 "${testcvs} -q update -j br2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into file1 -rcsmerge: warning: conflicts during merge -U file2" - dotest join3-13 "cat file1" \ -"initial contents of file1 -[<]<<<<<< file1 -br1:line1 -[=]====== -trunk:line1 -[>]>>>>>> 1\.2" - rm file1 - - # OK, we'll try the same thing with a revision on br2. - dotest join3-14 "${testcvs} -q update -r br2 file1" \ -"${PROG} update: warning: file1 was lost -U file1" "U file1" - echo 'br2:line1' >>file1 - dotest join3-15 "${testcvs} -q ci -m modify file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2\.2\.1; previous revision: 1\.2 -done" - - # OK, now we can join br2 to br1 - dotest join3-16 "${testcvs} -q update -r br1 file1" "[UP] file1" - # It may seem odd, to merge a higher branch into a lower - # branch, but in fact CVS defines the ancestor as 1.1 - # and so it merges both the 1.1->1.2 and 1.2->1.2.2.1 changes. - # This seems like a reasonably plausible behavior. - dotest join3-17 "${testcvs} -q update -j br2 file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.1 -retrieving revision 1\.2\.2\.1 -Merging differences between 1\.1 and 1\.2\.2\.1 into file1 -rcsmerge: warning: conflicts during merge" - dotest join3-18 "cat file1" \ -"initial contents of file1 -[<]<<<<<< file1 -br1:line1 -[=]====== -trunk:line1 -br2:line1 -[>]>>>>>> 1\.2\.2\.1" - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - join4) - # Like join, but with local (uncommitted) modifications. - - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir 1 - cd 1 - dotest join4-1 "${testcvs} -q co first-dir" '' - - cd first-dir - - # Add two files. - echo 'first revision of file3' > file3 - echo 'first revision of file4' > file4 - echo 'first revision of file6' > file6 - echo 'first revision of file8' > file8 - echo 'first revision of file9' > file9 - dotest join4-2 "${testcvs} add file3 file4 file6 file8 file9" \ -"${PROG}"' add: scheduling file `file3'\'' for addition -'"${PROG}"' add: scheduling file `file4'\'' for addition -'"${PROG}"' add: scheduling file `file6'\'' for addition -'"${PROG}"' add: scheduling file `file8'\'' for addition -'"${PROG}"' add: scheduling file `file9'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add these files permanently' - - dotest join4-3 "${testcvs} -q commit -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file3,v -done -Checking in file3; -${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file6,v -done -Checking in file6; -${CVSROOT_DIRNAME}/first-dir/file6,v <-- file6 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file8,v -done -Checking in file8; -${CVSROOT_DIRNAME}/first-dir/file8,v <-- file8 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file9,v -done -Checking in file9; -${CVSROOT_DIRNAME}/first-dir/file9,v <-- file9 -initial revision: 1\.1 -done" - - # Make a branch. - dotest join4-4 "${testcvs} -q tag -b branch ." \ -'T file3 -T file4 -T file6 -T file8 -T file9' - - # Add file10 - echo 'first revision of file10' > file10 - dotest join4-7a "${testcvs} add file10" \ -"${PROG}"' add: scheduling file `file10'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest join4-7b "${testcvs} -q ci -mx ." \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file10,v -done -Checking in file10; -${CVSROOT_DIRNAME}/first-dir/file10,v <-- file10 -initial revision: 1\.1 -done" - - # Add file2 and file7, modify file4, and remove - # file6, file8, file9, and file10. - echo 'first revision of file2' > file2 - echo 'second revision of file4' > file4 - echo 'first revision of file7' > file7 - rm file6 file8 file9 file10 - dotest join4-5 "${testcvs} add file2 file7" \ -"${PROG}"' add: scheduling file `file2'\'' for addition -'"${PROG}"' add: scheduling file `file7'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add these files permanently' - dotest join4-6 "${testcvs} rm file6 file8 file9 file10" \ -"${PROG}"' remove: scheduling `file6'\'' for removal -'"${PROG}"' remove: scheduling `file8'\'' for removal -'"${PROG}"' remove: scheduling `file9'\'' for removal -'"${PROG}"' remove: scheduling `file10'\'' for removal -'"${PROG}"' remove: use .'"${PROG}"' commit. to remove these files permanently' - - # Check out the branch. - cd ../.. - mkdir 2 - cd 2 - dotest join4-8 "${testcvs} -q co -r branch first-dir" \ -'U first-dir/file3 -U first-dir/file4 -U first-dir/file6 -U first-dir/file8 -U first-dir/file9' - - cd first-dir - - # Modify the files on the branch, so that T1 is not an - # ancestor of the main line, and add file5 - echo 'first branch revision of file3' > file3 - echo 'first branch revision of file4' > file4 - echo 'first branch revision of file5' > file5 - echo 'first branch revision of file6' > file6 - echo 'first branch revision of file9' > file9 - dotest join4-9 "${testcvs} add file5" \ -"${PROG}"' add: scheduling file `file5'\'' for addition on branch `branch'\'' -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest join4-10 "${testcvs} -q ci -mx ." \ -"Checking in file3; -${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file5,v -done -Checking in file5; -${CVSROOT_DIRNAME}/first-dir/Attic/file5,v <-- file5 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in file6; -${CVSROOT_DIRNAME}/first-dir/file6,v <-- file6 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in file9; -${CVSROOT_DIRNAME}/first-dir/file9,v <-- file9 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - # Tag the current revisions on the branch. - dotest join4-11 "${testcvs} -q tag T1 ." \ -'T file3 -T file4 -T file5 -T file6 -T file8 -T file9' - - # Add file1 and file2, modify file9, and remove the other files. - echo 'first branch revision of file1' > file1 - echo 'first branch revision of file2' > file2 - echo 'second branch revision of file9' > file9 - rm file3 file4 file5 file6 - dotest join4-12 "${testcvs} add file1 file2" \ -"${PROG}"' add: scheduling file `file1'\'' for addition on branch `branch'\'' -'"${PROG}"' add: scheduling file `file2'\'' for addition on branch `branch'\'' -'"${PROG}"' add: use .'"${PROG}"' commit. to add these files permanently' - dotest join4-13 "${testcvs} rm file3 file4 file5 file6" \ -"${PROG}"' remove: scheduling `file3'\'' for removal -'"${PROG}"' remove: scheduling `file4'\'' for removal -'"${PROG}"' remove: scheduling `file5'\'' for removal -'"${PROG}"' remove: scheduling `file6'\'' for removal -'"${PROG}"' remove: use .'"${PROG}"' commit. to remove these files permanently' - dotest join4-14 "${testcvs} -q ci -mx ." \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/Attic/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/Attic/file2,v <-- file2 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Removing file3; -${CVSROOT_DIRNAME}/first-dir/file3,v <-- file3 -new revision: delete; previous revision: 1\.1\.2\.1 -done -Removing file4; -${CVSROOT_DIRNAME}/first-dir/file4,v <-- file4 -new revision: delete; previous revision: 1\.1\.2\.1 -done -Removing file5; -${CVSROOT_DIRNAME}/first-dir/Attic/file5,v <-- file5 -new revision: delete; previous revision: 1\.1\.2\.1 -done -Removing file6; -${CVSROOT_DIRNAME}/first-dir/file6,v <-- file6 -new revision: delete; previous revision: 1\.1\.2\.1 -done -Checking in file9; -${CVSROOT_DIRNAME}/first-dir/file9,v <-- file9 -new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 -done" - - # Tag the current revisions on the branch. - dotest join4-15 "${testcvs} -q tag T2 ." \ -'T file1 -T file2 -T file8 -T file9' - - # Modify file4 locally, and do an update with a merge. - cd ../../1/first-dir - echo 'third revision of file4' > file4 - dotest join4-18 "$testcvs -q update -jT1 -jT2 ." \ -"U file1 -R file10 -A file2 -$PROG update: file file2 exists, but has been added in revision T2 -$PROG update: scheduling file3 for removal -M file4 -$PROG update: file file4 has been removed in revision T2, but the destination is incompatibly modified -C file4 -R file6 -A file7 -R file8 -R file9 -$PROG update: file file9 does not exist, but is present in revision T2" - - # Verify that the right changes have been scheduled. - dotest_fail join4-19 "${testcvs} -q update" \ -'A file1 -R file10 -A file2 -R file3 -C file4 -R file6 -A file7 -R file8 -R file9' - - cd ../.. - - rm -r 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - join5) - # This test verifies that CVS can handle filenames starting with a - # dash (`-') properly. What used to happen was that CVS handled it - # just fine, until it went to pass them as arguments to the diff - # library, at which point it neglected to pass `--' before the file - # list, causing the diff library to attempt to interpret the file - # name as an argument. - mkdir join5; cd join5 - mkdir 1; cd 1 - dotest join5-init-1 "${testcvs} -Q co -l ." - mkdir join5 - dotest join5-init-2 "${testcvs} -Q add join5" - cd join5 - echo "there once was a file from harrisburg" >-file - echo "who's existance it seems was quiteabsurd" >>-file - dotest join5-init-3 "${testcvs} -Q add -- -file" - dotest join5-init-4 "${testcvs} -q ci -minitial" \ -"RCS file: ${CVSROOT_DIRNAME}/join5/-file,v -done -Checking in -file; -${CVSROOT_DIRNAME}/join5/-file,v <-- -file -initial revision: 1\.1 -done" - cd ../.. - - mkdir 2; cd 2 - dotest join5-init-5 "${testcvs} -Q co join5" - cd join5 - echo "it tested for free" >>-file - echo "when paid it should be" >>-file - dotest join5-init-4 "${testcvs} -q ci -msecond" \ -"Checking in -file; -${CVSROOT_DIRNAME}/join5/-file,v <-- -file -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../.. - - cd 1/join5 - echo "but maybe it could charge bytheword" >>-file - # This is the test that used to spew complaints from diff3: - dotest join5 "${testcvs} up" \ -"${PROG} update: Updating \. -RCS file: ${CVSROOT_DIRNAME}/join5/-file,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into -file -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in -file -C -file" - cd ../.. - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd .. - rm -r join5 - rm -rf ${CVSROOT_DIRNAME}/join5 - ;; - - join6) - mkdir join6; cd join6 - mkdir 1; cd 1 - dotest join6-init-1 "${testcvs} -Q co -l ." - mkdir join6 - dotest join6-init-2 "${testcvs} -Q add join6" - cd join6 - echo aaa >temp.txt - echo bbb >>temp.txt - echo ccc >>temp.txt - dotest join6-1 "${testcvs} -Q add temp.txt" - dotest join6-2 "${testcvs} -q commit -minitial temp.txt" \ -"RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v -done -Checking in temp\.txt; -${CVSROOT_DIRNAME}/join6/temp.txt,v <-- temp\.txt -initial revision: 1\.1 -done" - cp temp.txt temp2.txt - echo ddd >>temp.txt - dotest join6-3 "${testcvs} -q commit -madd temp.txt" \ -"Checking in temp\.txt; -${CVSROOT_DIRNAME}/join6/temp.txt,v <-- temp\.txt -new revision: 1\.2; previous revision: 1\.1 -done" - - # The case where the merge target is up-to-date and its base revision - # matches the second argument to -j: CVS doesn't bother attempting - # the merge since it already knows that the target contains the - # change. - dotest join6-3.3 "${testcvs} update -j1.1 -j1.2 temp.txt" \ -"temp\.txt already contains the differences between 1\.1 and 1\.2" - dotest join6-3.4 "${testcvs} diff temp.txt" "" - - # The case where the merge target is modified but already contains - # the change. - echo bbb >temp.txt - echo ccc >>temp.txt - echo ddd >>temp.txt - dotest join6-3.5 "${testcvs} update -j1.1 -j1.2 temp.txt" \ -"M temp\.txt -RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into temp\.txt -temp\.txt already contains the differences between 1\.1 and 1\.2" - dotest_fail join6-3.6 "${testcvs} diff temp.txt" \ -"Index: temp\.txt -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v -retrieving revision 1\.2 -diff -r1\.2 temp.txt -1d0 -< aaa" - - cp temp2.txt temp.txt - dotest_fail join6-4 "${testcvs} diff temp.txt" \ -"Index: temp.txt -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v -retrieving revision 1\.2 -diff -r1\.2 temp\.txt -4d3 -< ddd" - - dotest join6-5 "${testcvs} update -j1.1 -j1.2 temp.txt" \ -"M temp\.txt -RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into temp\.txt" - dotest join6-6 "${testcvs} diff temp.txt" "" - mv temp.txt temp3.txt - dotest join6-7 "sed 's/ddd/dddd/' < temp3.txt > temp.txt" "" - dotest join6-8 "${testcvs} update -j1.1 -j1.2 temp.txt" \ -"M temp\.txt -RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into temp\.txt -rcsmerge: warning: conflicts during merge" - dotest_fail join6-9 "${testcvs} diff temp.txt" \ -"Index: temp\.txt -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v -retrieving revision 1\.2 -diff -r1\.2 temp\.txt -3a4,6 -> <<<<<<< temp\.txt -> dddd -> ======= -4a8 -> >>>>>>> 1\.2" - cp temp2.txt temp.txt - dotest join6-10 "${testcvs} -q ci -m del temp.txt" \ -"Checking in temp\.txt; -${CVSROOT_DIRNAME}/join6/temp.txt,v <-- temp\.txt -new revision: 1\.3; previous revision: 1\.2 -done" - cp temp3.txt temp.txt - dotest_fail join6-11 "${testcvs} diff temp.txt" \ -"Index: temp\.txt -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v -retrieving revision 1\.3 -diff -r1\.3 temp\.txt -3a4 -> ddd" - dotest join6-12 "${testcvs} update -j1.2 -j1.3 temp.txt" \ -"M temp\.txt -RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v -retrieving revision 1\.2 -retrieving revision 1\.3 -Merging differences between 1\.2 and 1\.3 into temp\.txt" - dotest join6-13 "${testcvs} diff temp.txt" "" - - # The case where the merge target wasn't created until after the - # first tag was applied - rm temp2.txt temp3.txt - dotest join6-20 "${testcvs} -q tag -r1.1 t1" \ -"T temp.txt" - echo xxx >temp2.txt - dotest join6-21 "${testcvs} -Q add temp2.txt" - dotest join6-22 "${testcvs} -q ci -m." \ -"RCS file: ${CVSROOT_DIRNAME}/join6/temp2.txt,v -done -Checking in temp2\.txt; -${CVSROOT_DIRNAME}/join6/temp2\.txt,v <-- temp2\.txt -initial revision: 1\.1 -done" - dotest join6-23 "${testcvs} -q tag t2" \ -"T temp.txt -T temp2.txt" - echo xxx >>temp.txt - dotest join6-24 "${testcvs} -q ci -m." \ -"Checking in temp\.txt; -${CVSROOT_DIRNAME}/join6/temp.txt,v <-- temp\.txt -new revision: 1\.4; previous revision: 1\.3 -done" - dotest join6-25 "${testcvs} -q up -jt1 -jt2" \ -"RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v -retrieving revision 1\.1 -retrieving revision 1\.3 -Merging differences between 1\.1 and 1\.3 into temp.txt -temp.txt already contains the differences between 1\.1 and 1\.3 -temp2.txt already contains the differences between creation and 1\.1" - - # Now for my next trick: delete the file, recreate it, and - # try to merge - dotest join6-30 "${testcvs} -q rm -f temp2.txt" \ -"${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest join6-31 "${testcvs} -q ci -m. temp2.txt" \ -"Removing temp2\.txt; -${CVSROOT_DIRNAME}/join6/temp2\.txt,v <-- temp2\.txt -new revision: delete; previous revision: 1\.1 -done" - echo new >temp2.txt - # FIXCVS: Local and remote really shouldn't be different and there - # really shouldn't be two different status lines for temp2.txt - if $remote; then - dotest_fail join6-32 "${testcvs} -q up -jt1 -jt2" \ -"? temp2\.txt -RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v -retrieving revision 1\.1 -retrieving revision 1\.3 -Merging differences between 1\.1 and 1\.3 into temp.txt -temp.txt already contains the differences between 1\.1 and 1\.3 -${PROG} update: move away \./temp2\.txt; it is in the way -C temp2\.txt" - else - dotest join6-32 "${testcvs} -q up -jt1 -jt2" \ -"RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v -retrieving revision 1\.1 -retrieving revision 1\.3 -Merging differences between 1\.1 and 1\.3 into temp.txt -temp.txt already contains the differences between 1\.1 and 1\.3 -${PROG} update: use .${PROG} add. to create an entry for temp2\.txt -U temp2\.txt -? temp2\.txt" - fi - - cd ../../.. - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -r join6 - rm -rf ${CVSROOT_DIRNAME}/join6 - ;; - - join7) - # This test deals with joins that happen with the -n switch - mkdir join7; cd join7 - mkdir impdir; cd impdir - echo aaa >temp.txt - echo bbb >>temp.txt - echo ccc >>temp.txt - dotest join7-1 \ -"${testcvs} -Q import -minitial join7 vendor vers-1" \ -"" - cd .. - dotest join7-2 "${testcvs} -Q co join7" "" - cd join7 - echo ddd >> temp.txt - dotest join7-3 "${testcvs} -Q ci -madded-line temp.txt" \ -"Checking in temp.txt; -$CVSROOT_DIRNAME/join7/temp.txt,v <-- temp.txt -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../impdir - echo aaaa >temp.txt - echo bbbb >>temp.txt - echo ccc >>temp.txt - echo eee >>temp.txt - dotest join7-4 \ -"${testcvs} -Q import -minitial join7 vendor vers-2" \ -"" - cd ../join7 - dotest join7-5 \ -"${testcvs} -n update -jvers-1 -jvers-2 temp.txt" \ -"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.2 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt -rcsmerge: warning: conflicts during merge" - touch temp.txt - dotest join7-6 "${testcvs} -n update -jvers-1 -jvers-2 temp.txt" \ -"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.2 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt -rcsmerge: warning: conflicts during merge" \ -"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.2 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt -rcsmerge: warning: conflicts during merge" - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd ../.. - rm -r join7 - rm -rf $CVSROOT_DIRNAME/join7 - ;; - - - - join8) - # In this test case, we have 2 projects, one called "pvcs" and one - # called "project". The "pvcs" project has modified the file, while - # the "project" project has caused a deletion. When "project" is - # merged into "pvcs", we expect CVS to detect a conflict. - mkdir join8; cd join8 - mkdir combine - mkdir base - mkdir pvcs - mkdir project - - echo "aaa" >base/file.txt - echo "bbb" >pvcs/file.txt - echo "ccc" >project/xxx.txt - - cd base - dotest join8-1 \ -"$testcvs import -b 1.1.101 -ko -m 'base import' join8 base base-1" \ -"N join8/file\.txt - -No conflicts created by this import" - - cd ../pvcs - dotest join8-2 \ -"$testcvs import -b 1.1.201 -ko -m 'pvcs import' join8 pvcs pvcs-1" \ -"C join8/file\.txt - -1 conflicts created by this import. -Use the following command to help the merge: - - $PROG checkout -j<prev_rel_tag> -jpvcs-1 join8" - - cd ../project - dotest join8-3 \ -"$testcvs import -b 1.1.301 -ko -m 'project import' join8 project project-1" \ -"N join8/xxx\.txt - -No conflicts created by this import" - - cd .. - dotest join8-4 \ -"$testcvs checkout -r pvcs-1 -j base-1 -j project-1 -d combine join8" \ -"$PROG checkout: Updating combine -U combine/file\.txt -$PROG checkout: file combine/file\.txt has been removed in revision project-1, but the destination is incompatibly modified -C combine/file.txt -U combine/xxx\.txt" - - dotest join8-5 \ -"$testcvs -Q up -pr base-1 combine/file.txt >combine/file.txt" - - dotest join8-6 \ -"$testcvs up -j base-1 -j project-1 combine" \ -"$PROG update: Updating combine -M combine/file\.txt -$PROG update: scheduling combine/file\.txt for removal -A combine/xxx\.txt -$PROG update: file combine/xxx\.txt exists, but has been added in revision project-1" - cd .. - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - rm -r join8 - rm -rf $CVSROOT_DIRNAME/join8 - ;; - - - - join9) - # In this test case, we have 2 projects, one called "pvcs" and one - # called "project". The "pvcs" project has not modified the file, - # while the "project" project has caused a deletion. When "project" - # is merged into "pvcs", we expect CVS to remove the file without - # fuss, as there is no conflict. - mkdir join9; cd join9 - mkdir combine - mkdir base - mkdir pvcs - mkdir project - - echo "aaa" >base/file.txt - echo "aaa" >pvcs/file.txt - echo "ccc" >project/xxx.txt - - cd base - dotest join9-1 \ -"$testcvs import -b 1.1.101 -ko -m 'base import' join9 base base-1" \ -"N join9/file\.txt - -No conflicts created by this import" - - cd ../pvcs - dotest join9-2 \ -"$testcvs import -b 1.1.201 -ko -m 'pvcs import' join9 pvcs pvcs-1" \ -"C join9/file\.txt - -1 conflicts created by this import. -Use the following command to help the merge: - - $PROG checkout -j<prev_rel_tag> -jpvcs-1 join9" - - cd ../project - dotest join9-3 \ -"$testcvs import -b 1.1.301 -ko -m 'project import' join9 project project-1" \ -"N join9/xxx\.txt - -No conflicts created by this import" - - cd .. - dotest join9-4 \ -"$testcvs checkout -r pvcs-1 -j base-1 -j project-1 -d combine join9" \ -"$PROG checkout: Updating combine -U combine/file\.txt -$PROG checkout: scheduling combine/file\.txt for removal -U combine/xxx\.txt" - - cd .. - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - rm -r join9 - rm -rf $CVSROOT_DIRNAME/join9 - ;; - - - - join-readonly-conflict) - # Previously, only tests 1 & 11 were being tested. I added the - # intermediate dotest's to try and diagnose a different failure - # - # Demonstrate that cvs-1.9.29 can fail on 2nd and subsequent - # conflict-evoking join attempts. - # Even with that version of CVS, This test failed only in - # client-server mode, and would have been noticed in normal - # operation only for files that were read-only (either due to - # use of cvs' global -r option, setting the CVSREAD envvar, - # or use of watch lists). - mkdir join-readonly-conflict; cd join-readonly-conflict - dotest join-readonly-conflict-1 "$testcvs -q co -l ." '' - module=join-readonly-conflict - mkdir $module - $testcvs -q add $module >>$LOGFILE 2>&1 - cd $module - - file=m - echo trunk > $file - dotest join-readonly-conflict-2 "$testcvs -Q add $file" '' - - dotest join-readonly-conflict-3 "$testcvs -q ci -m . $file" \ -"RCS file: $CVSROOT_DIRNAME/$module/$file,v -done -Checking in $file; -$CVSROOT_DIRNAME/$module/$file,v <-- $file -initial revision: 1\.1 -done" - - dotest join-readonly-conflict-4 "$testcvs tag -b B $file" "T $file" - dotest join-readonly-conflict-5 "$testcvs -q update -rB $file" \ -"[UP] $file" - echo branch B > $file - dotest join-readonly-conflict-6 "$testcvs -q ci -m . $file" \ -"Checking in $file; -$CVSROOT_DIRNAME/$module/$file,v <-- $file -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - rm $file - dotest join-readonly-conflict-7 "$testcvs -Q update -A $file" '' - # Make sure $file is read-only. This can happen more realistically - # via patch -- which could be used to apply a delta, yet would - # preserve a file's read-only permissions. - echo conflict > $file; chmod u-w $file - dotest join-readonly-conflict-8 "$testcvs update -r B $file" \ -"RCS file: $CVSROOT_DIRNAME/$module/$file,v -retrieving revision 1\.1 -retrieving revision 1\.1\.2\.1 -Merging differences between 1\.1 and 1\.1\.2\.1 into $file -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in $file -C $file" - - # restore to the trunk - rm -f $file - dotest join-readonly-conflict-9 "$testcvs -Q update -A $file" '' - - # This one would fail because cvs couldn't open the existing - # (and read-only) .# file for writing. - echo conflict > $file - - # verify that the backup file is not writable - if test -w ".#$file.1.1"; then - fail "join-readonly-conflict-10 : .#$file.1.1 is writable" - else - pass "join-readonly-conflict-10" - fi - dotest join-readonly-conflict-11 "$testcvs update -r B $file" \ -"RCS file: $CVSROOT_DIRNAME/$module/$file,v -retrieving revision 1\.1 -retrieving revision 1\.1\.2\.1 -Merging differences between 1\.1 and 1\.1\.2\.1 into $file -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in $file -C m" - - cd ../.. - if $keep; then :; else - rm -rf join-readonly-conflict - rm -rf $CVSROOT_DIRNAME/$module - fi - ;; - - 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 ${CVSROOT_DIRNAME}/x/b,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - - cd ../.. - rm -rf 1 - rm -rf ${CVSROOT_DIRNAME}/$module - ;; - - join-admin-2) - # Show that when a merge (via update -kk -jtag1 -jtag2) first - # removes a file, then modifies another containing an $Id...$ line, - # the resulting file contains the unexpanded `$Id.$' string, as - # -kk requires. - mkdir 1; cd 1 - dotest join-admin-2-1 "$testcvs -q co -l ." '' - module=x - mkdir $module - dotest join-admin-2-2 "$testcvs -q add $module" \ -"Directory ${CVSROOT_DIRNAME}/x added to the repository" - cd $module - - # Create a file so applying the first tag works. - echo '$''Id$' > e0 - cp e0 e - dotest join-admin-2-3 "$testcvs -Q add e" '' - dotest join-admin-2-4 "$testcvs -Q ci -m. e" \ -"RCS file: ${CVSROOT_DIRNAME}/x/e,v -done -Checking in e; -${CVSROOT_DIRNAME}/x/e,v <-- e -initial revision: 1\.1 -done" - - dotest join-admin-2-5 "$testcvs -Q tag -b T" '' "${QUESTION} e0" - dotest join-admin-2-6 "$testcvs -Q update -r T" '' "${QUESTION} e0" - cp e0 e - dotest join-admin-2-7 "$testcvs -Q ci -m. e" \ -"Checking in e; -${CVSROOT_DIRNAME}/x/e,v <-- e -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - dotest join-admin-2-8 "$testcvs -Q update -A" '' "${QUESTION} e0" - dotest join-admin-2-9 "$testcvs -Q tag -b M1" '' "${QUESTION} e0" - - echo '$''Id$' > b - dotest join-admin-2-10 "$testcvs -Q add b" '' - cp e0 e - dotest join-admin-2-11 "$testcvs -Q ci -m. b e" \ -"RCS file: ${CVSROOT_DIRNAME}/x/b,v -done -Checking in b; -${CVSROOT_DIRNAME}/x/b,v <-- b -initial revision: 1\.1 -done -Checking in e; -${CVSROOT_DIRNAME}/x/e,v <-- e -new revision: 1\.2; previous revision: 1\.1 -done" - - dotest join-admin-2-12 "$testcvs -Q tag -b M2" '' "${QUESTION} e0" - - dotest join-admin-2-13 "$testcvs -Q update -r T" '' "${QUESTION} e0" - dotest join-admin-2-14 "$testcvs update -kk -jM1 -jM2" \ -"${PROG} update: Updating . -U b -U e -RCS file: ${CVSROOT_DIRNAME}/x/e,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into e -e already contains the differences between 1\.1 and 1\.2 -${QUESTION} e0" \ -"${QUESTION} e0 -${PROG} update: Updating . -U b -U e -RCS file: ${CVSROOT_DIRNAME}/x/e,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into e -e already contains the differences between 1\.1 and 1\.2" - - # Verify that the $Id.$ string is not expanded. - dotest join-admin-2-15 "cat e" '$''Id$' - - cd ../.. - rm -rf 1 - rm -rf ${CVSROOT_DIRNAME}/$module - ;; - - join-rm) - # This first half of this test checks that a single-argument merge - # from a branch is capable of removing files. - # - # The second half verifies that an update to another location with an - # uncommitted removal will transfer the destination branch of the - # removal. - - module=join-rm - mkdir $module; cd $module - - dotest join-rm-init-1 "$testcvs -q co -l ." '' - mkdir $module - dotest join-rm-init-2 "$testcvs -q add $module" \ -"Directory $CVSROOT_DIRNAME/$module added to the repository" - cd $module - - # add some files. - touch a b c d e f g - dotest join-rm-init-3 "$testcvs -Q add a b c d e f g" - dotest join-rm-init-4 "$testcvs -Q ci -m add-em" \ -"RCS file: $CVSROOT_DIRNAME/join-rm/a,v -done -Checking in a; -$CVSROOT_DIRNAME/join-rm/a,v <-- a -initial revision: 1\.1 -done -RCS file: $CVSROOT_DIRNAME/join-rm/b,v -done -Checking in b; -$CVSROOT_DIRNAME/join-rm/b,v <-- b -initial revision: 1\.1 -done -RCS file: $CVSROOT_DIRNAME/join-rm/c,v -done -Checking in c; -$CVSROOT_DIRNAME/join-rm/c,v <-- c -initial revision: 1\.1 -done -RCS file: $CVSROOT_DIRNAME/join-rm/d,v -done -Checking in d; -$CVSROOT_DIRNAME/join-rm/d,v <-- d -initial revision: 1\.1 -done -RCS file: $CVSROOT_DIRNAME/join-rm/e,v -done -Checking in e; -$CVSROOT_DIRNAME/join-rm/e,v <-- e -initial revision: 1\.1 -done -RCS file: $CVSROOT_DIRNAME/join-rm/f,v -done -Checking in f; -$CVSROOT_DIRNAME/join-rm/f,v <-- f -initial revision: 1\.1 -done -RCS file: $CVSROOT_DIRNAME/join-rm/g,v -done -Checking in g; -$CVSROOT_DIRNAME/join-rm/g,v <-- g -initial revision: 1\.1 -done" - - # create the branch and update to it - dotest join-rm-init-5 "$testcvs -Q tag -b br" - dotest join-rm-init-6 "$testcvs -Q up -rbr" - - # remove a few files from the branch - dotest join-rm-init-7 "$testcvs -Q rm -f b d g" - dotest join-rm-init-8 "$testcvs -Q ci -mrm" \ -"Removing b; -$CVSROOT_DIRNAME/join-rm/b,v <-- b -new revision: delete; previous revision: 1\.1 -done -Removing d; -$CVSROOT_DIRNAME/join-rm/d,v <-- d -new revision: delete; previous revision: 1\.1 -done -Removing g; -$CVSROOT_DIRNAME/join-rm/g,v <-- g -new revision: delete; previous revision: 1\.1 -done" - - # update to the trunk - dotest join-rm-init-9 "$testcvs -Q up -A" - - # now for the test - try and merge the removals. - dotest join-rm-1 "$testcvs -q up -jbr" \ -"$PROG update: scheduling b for removal -$PROG update: scheduling d for removal -$PROG update: scheduling g for removal" - - # And make sure the merge took - dotest join-rm-2 "$testcvs -qn up" \ -"R b -R d -R g" - - dotest join-rm-3 "$testcvs -q ci -m 'save the merge'" \ -"Removing b; -$CVSROOT_DIRNAME/join-rm/b,v <-- b -new revision: delete; previous revision: 1\.1 -done -Removing d; -$CVSROOT_DIRNAME/join-rm/d,v <-- d -new revision: delete; previous revision: 1\.1 -done -Removing g; -$CVSROOT_DIRNAME/join-rm/g,v <-- g -new revision: delete; previous revision: 1\.1 -done" - - # and verify that it was the head revision which was removed. - dotest join-rm-4 "$testcvs -q log b" " -RCS file: $CVSROOT_DIRNAME/join-rm/Attic/b,v -Working file: b -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - br: 1\.1\.0\.2 -keyword substitution: kv -total revisions: 3; selected revisions: 3 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: $username; state: dead; lines: ${PLUS}0 -0 -save the merge ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -branches: 1.1.2; -add-em ----------------------------- -revision 1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: $username; state: dead; lines: ${PLUS}0 -0 -rm -=============================================================================" - - # go back to the branch to set up for the second set of tests - dotest join-rm-init-10 "$testcvs -Q up -rbr" - dotest join-rm-init-11 "$testcvs -Q rm -f a" - dotest join-rm-init-12 "$testcvs -Q ci -m rma" \ -"Removing a; -$CVSROOT_DIRNAME/join-rm/a,v <-- a -new revision: delete; previous revision: 1\.1 -done" - - # now the test: update to the trunk - # - # FIXCVS: This update should merge the removal to the trunk. It does - # not. - dotest join-rm-5 "$testcvs -q up -A" \ -'U a -U c -U e -U f' - - # and verify that there is no sticky tag - dotest join-rm-6 "$testcvs status a" \ -"=================================================================== -File: a Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 $CVSROOT_DIRNAME/join-rm/a,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd ../.. - rm -rf $CVSROOT_DIRNAME/$module - rm -r $module - ;; - - new) # look for stray "no longer pertinent" messages. - mkdir ${CVSROOT_DIRNAME}/first-dir - - if ${CVS} co first-dir ; then - pass 117 - else - fail 117 - fi - - cd first-dir - touch a - - if ${CVS} add a 2>>${LOGFILE}; then - pass 118 - else - fail 118 - fi - - if ${CVS} ci -m added >>${LOGFILE} 2>&1; then - pass 119 - else - fail 119 - fi - - rm a - - if ${CVS} rm a 2>>${LOGFILE}; then - pass 120 - else - fail 120 - fi - - if ${CVS} ci -m removed >>${LOGFILE} ; then - pass 121 - else - fail 121 - fi - - if ${CVS} update -A 2>&1 | grep longer ; then - fail 122 - else - pass 122 - fi - - if ${CVS} update -rHEAD 2>&1 | grep longer ; then - fail 123 - else - pass 123 - fi - - cd .. - rm -r first-dir - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - newb) - # Test removing a file on a branch and then checking it out. - - # We call this "newb" only because it, like the "new" tests, - # has something to do with "no longer pertinent" messages. - # Not necessarily the most brilliant nomenclature. - - # Create file 'a'. - mkdir ${CVSROOT_DIRNAME}/first-dir - dotest newb-123a "${testcvs} -q co first-dir" '' - cd first-dir - touch a - dotest newb-123b "${testcvs} add a" \ -"${PROG} add: scheduling file .a. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest newb-123c "${testcvs} -q ci -m added" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v -done -Checking in a; -${CVSROOT_DIRNAME}/first-dir/a,v <-- a -initial revision: 1\.1 -done" - - # Make a branch. - dotest newb-123d "${testcvs} -q tag -b branch" "T a" - - # Check out the branch. - cd .. - rm -r first-dir - mkdir 1 - cd 1 - dotest newb-123e "${testcvs} -q co -r branch first-dir" \ -"U first-dir/a" - - # Remove 'a' on another copy of the branch. - cd .. - mkdir 2 - cd 2 - dotest newb-123f "${testcvs} -q co -r branch first-dir" \ -"U first-dir/a" - cd first-dir - rm a - dotest newb-123g "${testcvs} rm a" \ -"${PROG} remove: scheduling .a. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest newb-123h "${testcvs} -q ci -m removed" \ -"Removing a; -${CVSROOT_DIRNAME}/first-dir/a,v <-- a -new revision: delete; previous revision: 1\.1 -done" - - # Check out the file on the branch. This should report - # that the file is not pertinent, but it should not - # say anything else. - cd .. - rm -r first-dir - dotest newb-123i "${testcvs} -q co -r branch first-dir/a" \ -"${PROG} checkout: warning: first-dir/a is not (any longer) pertinent" - - # Update the other copy, and make sure that a is removed. - cd ../1/first-dir - # "Entry Invalid" is a rather strange output here. Something like - # "Removed in Repository" would make more sense. - dotest newb-123j0 "${testcvs} status a" \ -"${PROG} status: a is no longer in the repository -=================================================================== -File: a Status: Entry Invalid - - Working revision: 1\.1.* - Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/a,v - Sticky Tag: branch (branch: 1\.1\.2) - Sticky Date: (none) - Sticky Options: (none)" - dotest newb-123j "${testcvs} -q update" \ -"${PROG} update: a is no longer in the repository" - - if test -f a; then - fail newb-123k - else - pass newb-123k - fi - - cd ../.. - rm -r 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - conflicts) - mkdir ${CVSROOT_DIRNAME}/first-dir - - mkdir 1 - cd 1 - - dotest conflicts-124 "${testcvs} -q co first-dir" '' - - cd first-dir - touch a - - dotest conflicts-125 "${testcvs} add a" \ -"${PROG} add: scheduling file .a. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest conflicts-126 "${testcvs} -q ci -m added" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v -done -Checking in a; -${CVSROOT_DIRNAME}/first-dir/a,v <-- a -initial revision: 1\.1 -done" - - cd ../.. - mkdir 2 - cd 2 - - dotest conflicts-126.5 "${testcvs} co -p first-dir" \ -"${PROG} checkout: Updating first-dir -=================================================================== -Checking out first-dir/a -RCS: ${CVSROOT_DIRNAME}/first-dir/a,v -VERS: 1\.1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*" - if ${CVS} co first-dir ; then - pass 127 - else - fail 127 - fi - cd first-dir - if test -f a; then - pass 127a - else - fail 127a - fi - - cd ../../1/first-dir - echo add a line >>a - mkdir dir1 - dotest conflicts-127b "${testcvs} add dir1" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir1 added to the repository" - dotest conflicts-128 "${testcvs} -q ci -m changed" \ -"Checking in a; -${CVSROOT_DIRNAME}/first-dir/a,v <-- a -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../.. - - # Similar to conflicts-126.5, but now the file has nonempty - # contents. - mkdir 3 - cd 3 - dotest conflicts-128.5 "${testcvs} co -p -l first-dir" \ -"${PROG} checkout: Updating first-dir -=================================================================== -Checking out first-dir/a -RCS: ${CVSROOT_DIRNAME}/first-dir/a,v -VERS: 1\.2 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -add a line" - cd .. - rmdir 3 - - # Now go over the to the other working directory and - # start testing conflicts - cd 2/first-dir - echo add a conflicting line >>a - dotest_fail conflicts-129 "${testcvs} -q ci -m changed" \ -"${PROG}"' commit: Up-to-date check failed for `a'\'' -'"${PROG}"' \[commit aborted\]: correct above errors first!' - mkdir dir1 - mkdir sdir - dotest conflicts-status-0 "${testcvs} status a" \ -"=================================================================== -File: a Status: Needs Merge - - Working revision: 1\.1.* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/a,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest conflicts-129a "${testcvs} -nq update a" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into a -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in a -C a" - dotest conflicts-130 "${testcvs} -q update" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into a -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in a -C a -${QUESTION} dir1 -${QUESTION} sdir" \ -"${QUESTION} dir1 -${QUESTION} sdir -RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into a -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in a -C a" - rmdir dir1 sdir - - dotest conflicts-status-1 "${testcvs} status a" \ -"=================================================================== -File: a Status: Unresolved Conflict - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/a,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest_fail conflicts-131 "${testcvs} -q ci -m try" \ -"${PROG} commit: file .a. had a conflict and has not been modified -${PROG} \[commit aborted\]: correct above errors first!" - - # Try to check in the file with the conflict markers in it. - # 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} commit: warning: file .a. seems to still contain conflict indicators" - - grep '^=======' aa >a - dotest conflicts-status-3 "${testcvs} -nq ci -m try a" \ -"${PROG} commit: warning: file .a. seems to still contain conflict indicators" - - grep '^>>>>>>>' aa >a - dotest conflicts-status-4 "${testcvs} -qn ci -m try a" \ -"${PROG} commit: 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 - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/a,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest conflicts-132 "${testcvs} -q ci -m try" \ -"${PROG} commit: warning: file .a. seems to still contain conflict indicators -Checking in a; -${CVSROOT_DIRNAME}/first-dir/a,v <-- a -new revision: 1\.3; previous revision: 1\.2 -done" - - # OK, the user saw the warning (good user), and now - # resolves it for real. - echo resolve conflict >a - dotest conflicts-status-6 "${testcvs} status a" \ -"=================================================================== -File: a Status: Locally Modified - - Working revision: 1\.3.* - Repository revision: 1\.3 ${CVSROOT_DIRNAME}/first-dir/a,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest conflicts-133 "${testcvs} -q ci -m resolved" \ -"Checking in a; -${CVSROOT_DIRNAME}/first-dir/a,v <-- a -new revision: 1\.4; previous revision: 1\.3 -done" - dotest conflicts-status-7 "${testcvs} status a" \ -"=================================================================== -File: a Status: Up-to-date - - Working revision: 1\.4.* - Repository revision: 1\.4 ${CVSROOT_DIRNAME}/first-dir/a,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - - # Now test that we can add a file in one working directory - # and have an update in another get it. - cd ../../1/first-dir - echo abc >abc - if ${testcvs} add abc >>${LOGFILE} 2>&1; then - pass 134 - else - fail 134 - fi - if ${testcvs} ci -m 'add abc' abc >>${LOGFILE} 2>&1; then - pass 135 - else - fail 135 - fi - cd ../../2 - mkdir first-dir/dir1 first-dir/sdir - dotest conflicts-136 "${testcvs} -q update first-dir" \ -'[UP] first-dir/abc -'"${QUESTION}"' first-dir/dir1 -'"${QUESTION}"' first-dir/sdir' \ -''"${QUESTION}"' first-dir/dir1 -'"${QUESTION}"' first-dir/sdir -[UP] first-dir/abc' - dotest conflicts-137 'test -f first-dir/abc' '' - rmdir first-dir/dir1 first-dir/sdir - - # Now test something similar, but in which the parent directory - # (not the directory in question) has the Entries.Static flag - # set. - cd ../1/first-dir - mkdir subdir - if ${testcvs} add subdir >>${LOGFILE}; then - pass 138 - else - fail 138 - fi - cd ../.. - mkdir 3 - cd 3 - if ${testcvs} -q co first-dir/abc first-dir/subdir \ - >>${LOGFILE}; then - pass 139 - else - fail 139 - fi - cd ../1/first-dir/subdir - echo sss >sss - if ${testcvs} add sss >>${LOGFILE} 2>&1; then - pass 140 - else - fail 140 - fi - if ${testcvs} ci -m adding sss >>${LOGFILE} 2>&1; then - pass 140 - else - fail 140 - fi - cd ../../../3/first-dir - if ${testcvs} -q update >>${LOGFILE}; then - pass 141 - else - fail 141 - fi - if test -f subdir/sss; then - pass 142 - else - fail 142 - fi - cd ../.. - rm -r 1 2 3 ; rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - conflicts2) - # More conflicts tests; separate from conflicts to keep each - # test a manageable size. - mkdir ${CVSROOT_DIRNAME}/first-dir - - mkdir 1 - cd 1 - - dotest conflicts2-142a1 "${testcvs} -q co first-dir" '' - - cd first-dir - touch a abc - - dotest conflicts2-142a2 "${testcvs} add a abc" \ -"${PROG} add: scheduling file .a. for addition -${PROG} add: scheduling file .abc. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest conflicts2-142a3 "${testcvs} -q ci -m added" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v -done -Checking in a; -${CVSROOT_DIRNAME}/first-dir/a,v <-- a -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -done -Checking in abc; -${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc -initial revision: 1\.1 -done" - - cd ../.. - mkdir 2 - cd 2 - - dotest conflicts2-142a4 "${testcvs} -q co first-dir" 'U first-dir/a -U first-dir/abc' - cd .. - - # BEGIN TESTS USING THE FILE A - # FIXME: would be cleaner to separate them out into their own - # tests; conflicts2 is getting long. - # Now test that if one person modifies and commits a - # file and a second person removes it, it is a - # conflict - cd 1/first-dir - echo modify a >>a - dotest conflicts2-142b2 "${testcvs} -q ci -m modify-a" \ -"Checking in a; -${CVSROOT_DIRNAME}/first-dir/a,v <-- a -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../../2/first-dir - rm a - dotest conflicts2-142b3 "${testcvs} rm a" \ -"${PROG} remove: scheduling .a. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest_fail conflicts2-142b4 "${testcvs} -q update" \ -"${PROG} update: conflict: removed a was modified by second party -C a" - # Resolve the conflict by deciding not to remove the file - # after all. - dotest_sort conflicts2-142b5 "${testcvs} add a" "U a -${PROG} add: a, version 1\.1, resurrected" - dotest conflicts2-142b5b1 "$testcvs status a" \ -"=================================================================== -File: a Status: Needs Patch - - Working revision: 1\.1.* - Repository revision: 1\.2 $CVSROOT_DIRNAME/first-dir/a,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest conflicts2-142b6 "${testcvs} -q update" 'U a' - - # Now one level up. - cd .. - dotest conflicts2-142b7 "${testcvs} rm -f first-dir/a" \ -"${PROG} remove: scheduling .first-dir/a. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - - if $remote; then - # Haven't investigated this one. - dotest_fail conflicts2-142b8r "$testcvs add first-dir/a" \ -"${PROG} add: in directory \.: -${PROG} \[add aborted\]: there is no version here; do '${PROG} checkout' first" - cd first-dir - else - dotest conflicts2-142b8 "${testcvs} add first-dir/a" \ -"U first-dir/a -${PROG} add: first-dir/a, version 1\.2, resurrected" - cd first-dir - # Now recover from the damage that the 142b8 test did. - dotest conflicts2-142b9 "${testcvs} rm -f a" \ -"${PROG} remove: scheduling .a. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - fi - - dotest_sort conflicts2-142b10 "${testcvs} add a" "U a -${PROG} add: a, version 1\.2, resurrected" - # As with conflicts2-142b6, check that things are normal again. - dotest conflicts2-142b11 "${testcvs} -q update" '' - cd ../.. - # END TESTS USING THE FILE A - - # Now test that if one person removes a file and - # commits it, and a second person removes it, is it - # not a conflict. - cd 1/first-dir - rm abc - dotest conflicts2-142c0 "${testcvs} rm abc" \ -"${PROG} remove: scheduling .abc. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest conflicts2-142c1 "${testcvs} -q ci -m remove-abc" \ -"Removing abc; -${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc -new revision: delete; previous revision: 1\.1 -done" - cd ../../2/first-dir - rm abc - dotest conflicts2-142c2 "${testcvs} rm abc" \ -"${PROG} remove: scheduling .abc. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest conflicts2-142c3 "${testcvs} update" \ -"${PROG} update: Updating \." - cd ../.. - - # conflicts2-142d*: test that if one party adds a file, and another - # party has a file of the same name, cvs notices - cd 1/first-dir - touch aa.c - echo 'contents unchanged' >same.c - dotest conflicts2-142d0 "${testcvs} add aa.c same.c" \ -"${PROG} add: scheduling file .aa\.c. for addition -${PROG} add: scheduling file .same\.c. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest conflicts2-142d1 "${testcvs} -q ci -m added" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aa\.c,v -done -Checking in aa\.c; -${CVSROOT_DIRNAME}/first-dir/aa\.c,v <-- aa\.c -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/same\.c,v -done -Checking in same\.c; -${CVSROOT_DIRNAME}/first-dir/same\.c,v <-- same\.c -initial revision: 1\.1 -done" - cd ../../2/first-dir - echo "don't you dare obliterate this text" >aa.c - echo 'contents unchanged' >same.c - # Note the discrepancy between local and remote in the handling - # of same.c. I kind - # of suspect that the local CVS behavior is the more useful one - # although I do sort of wonder whether we should make people run - # cvs add just to get them in that habit (also, trying to implement - # the local CVS behavior for remote without the cvs add seems - # pretty difficult). - if $remote; then - dotest_fail conflicts2-142d2 "${testcvs} -q update" \ -"${QUESTION} aa\.c -${QUESTION} same\.c -${PROG} update: move away \./aa\.c; it is in the way -C aa\.c -${PROG} update: move away \./same\.c; it is in the way -C same\.c" - else - dotest_fail conflicts2-142d2 "${testcvs} -q update" \ -"${PROG} [a-z]*: move away aa\.c; it is in the way -C aa\.c -U same\.c" - fi - dotest conflicts2-142d3 "${testcvs} -q status aa.c" \ -"${PROG} status: move away aa\.c; it is in the way -=================================================================== -File: aa\.c Status: Unresolved Conflict - - Working revision: No entry for aa\.c - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/aa\.c,v" - - # Could also be testing the case in which the cvs add happened - # before the commit by the other user. - # This message seems somewhat bogus. I mean, parallel development - # means that we get to work in parallel if we choose, right? And - # then at commit time it would be a conflict. - dotest_fail conflicts2-142d4 "${testcvs} -q add aa.c" \ -"${PROG} add: aa.c added independently by second party" - - # The user might want to see just what the conflict is. - # Don't bother, diff seems to kind of lose its mind, with or - # without -N. This is a CVS bug(s). - #dotest conflicts2-142d5 "${testcvs} -q diff -r HEAD -N aa.c" fixme - - # Now: "how can the user resolve this conflict", I hear you cry. - # Well, one way is to forget about the file in the working - # directory. - # Since it didn't let us do the add in conflicts2-142d4, there - # is no need to run cvs rm here. - #dotest conflicts2-142d6 "${testcvs} -q rm -f aa.c" fixme - dotest conflicts2-142d6 "rm aa.c" '' - dotest conflicts2-142d7 "${testcvs} -q update aa.c" "U aa\.c" - dotest conflicts2-142d8 "cat aa.c" '' - - # The other way is to use the version from the working directory - # instead of the version from the repository. Unfortunately, - # there doesn't seem to be any particularly clear way to do - # this (?). - - cd ../.. - - rm -r 1 2; rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - conflicts3) - # More tests of conflicts and/or multiple working directories - # in general. - - mkdir 1; cd 1 - dotest conflicts3-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest conflicts3-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd .. - mkdir 2; cd 2 - dotest conflicts3-3 "${testcvs} -q co -l first-dir" '' - cd ../1/first-dir - touch file1 file2 - dotest conflicts3-4 "${testcvs} add file1 file2" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest conflicts3-5 "${testcvs} -q ci -m add-them" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - cd ../../2/first-dir - # Check that -n doesn't make CVS lose its mind as it creates - # (or rather, doesn't) a new file. - dotest conflicts3-6 "${testcvs} -nq update" \ -"U file1 -U file2" - dotest_fail conflicts3-7 "test -f file1" '' - dotest conflicts3-8 "${testcvs} -q update" \ -"U file1 -U file2" - dotest conflicts3-9 "test -f file2" '' - - # OK, now remove two files at once - dotest conflicts3-10 "${testcvs} rm -f file1 file2" \ -"${PROG} remove: scheduling .file1. for removal -${PROG} remove: scheduling .file2. for removal -${PROG} remove: use .${PROG} commit. to remove these files permanently" - dotest conflicts3-11 "${testcvs} -q ci -m remove-them" \ -"Removing file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done -Removing file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: delete; previous revision: 1\.1 -done" - cd ../../1/first-dir - dotest conflicts3-12 "${testcvs} -n -q update" \ -"${PROG} update: file1 is no longer in the repository -${PROG} update: file2 is no longer in the repository" - dotest conflicts3-13 "${testcvs} -q update" \ -"${PROG} update: file1 is no longer in the repository -${PROG} update: file2 is no longer in the repository" - - # OK, now add a directory to both working directories - # and see that CVS doesn't lose its mind. - mkdir sdir - dotest conflicts3-14 "${testcvs} add sdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/sdir added to the repository" - touch sdir/sfile - dotest conflicts3-14a "${testcvs} add sdir/sfile" \ -"${PROG} add: scheduling file .sdir/sfile. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest conflicts3-14b "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/sfile,v -done -Checking in sdir/sfile; -${CVSROOT_DIRNAME}/first-dir/sdir/sfile,v <-- sfile -initial revision: 1\.1 -done" - - cd ../../2/first-dir - - # Create a CVS directory without the proper administrative - # files in it. This can happen for example if you hit ^C - # in the middle of a checkout. - mkdir sdir - mkdir sdir/CVS - # OK, in the local case CVS sees that the directory exists - # in the repository and recurses into it. In the remote case - # CVS can't see the repository and has no way of knowing - # that sdir is even a directory (stat'ing everything would be - # too slow). The remote behavior makes more sense to me (but - # would this affect other cases?). - if $remote; then - dotest conflicts3-15 "${testcvs} -q update" \ -"${QUESTION} sdir" - else - dotest conflicts3-15 "${testcvs} -q update" \ -"${QUESTION} sdir -${PROG} update: ignoring sdir (CVS/Repository missing)" - touch sdir/CVS/Repository - dotest conflicts3-16 "${testcvs} -q update" \ -"${QUESTION} sdir -${PROG} update: ignoring sdir (CVS/Entries missing)" - cd .. - dotest conflicts3-16a "${testcvs} -q update first-dir" \ -"${QUESTION} first-dir/sdir -${PROG} update: ignoring first-dir/sdir (CVS/Entries missing)" - cd first-dir - fi - rm -r sdir - - # OK, now the same thing, but the directory doesn't exist - # in the repository. - mkdir newdir - mkdir newdir/CVS - dotest conflicts3-17 "${testcvs} -q update" "${QUESTION} newdir" - echo "D/newdir////" >> CVS/Entries - dotest conflicts3-18 "${testcvs} -q update" \ -"${PROG} [a-z]*: ignoring newdir (CVS/Repository missing)" - touch newdir/CVS/Repository - dotest conflicts3-19 "${testcvs} -q update" \ -"${PROG} [a-z]*: ignoring newdir (CVS/Entries missing)" - cd .. - dotest conflicts3-20 "${testcvs} -q update first-dir" \ -"${PROG} [a-z]*: ignoring first-dir/newdir (CVS/Entries missing)" - cd first-dir - rm -r newdir - - # The previous tests have left CVS/Entries in something of a mess. - # While we "should" be able to deal with that (maybe), for now - # we just start over. - cd .. - rm -r first-dir - dotest conflicts3-20a "${testcvs} -q co -l first-dir" '' - cd first-dir - - dotest conflicts3-21 "${testcvs} -q update -d sdir" "U sdir/sfile" - rm -r sdir/CVS - dotest conflicts3-22 "${testcvs} -q update" "${QUESTION} sdir" - if $remote; then - dotest_fail conflicts3-23 "${testcvs} -q update -PdA" \ -"${QUESTION} sdir -${PROG} update: move away sdir/sfile; it is in the way -C sdir/sfile" - else - dotest conflicts3-23 "${testcvs} -q update -PdA" \ -"${QUESTION} sdir" - fi - - # Not that it should really affect much, but let's do the case - # where sfile has been removed. For example, suppose that sdir - # had been a CVS-controlled directory which was then removed - # by removing each file (and using update -P or some such). Then - # suppose that the build process creates an sdir directory which - # is not supposed to be under CVS. - rm -r sdir - dotest conflicts3-24 "${testcvs} -q update -d sdir" "U sdir/sfile" - rm sdir/sfile - dotest conflicts3-25 "${testcvs} rm sdir/sfile" \ -"${PROG} remove: scheduling .sdir/sfile. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest conflicts3-26 "${testcvs} ci -m remove sdir/sfile" \ -"Removing sdir/sfile; -${CVSROOT_DIRNAME}/first-dir/sdir/sfile,v <-- sfile -new revision: delete; previous revision: 1\.1 -done" - rm -r sdir/CVS - dotest conflicts3-27 "${testcvs} -q update" "${QUESTION} sdir" - dotest conflicts3-28 "${testcvs} -q update -PdA" \ -"${QUESTION} sdir" - - cd ../.. - - rm -r 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - conflicts4) - mkdir conflicts4; cd conflicts4 - mkdir 1; cd 1 - dotest conflicts4-1 "$testcvs -q co -l ." - mkdir first-dir - dotest conflicts4-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd .. - mkdir 2; cd 2 - dotest conflicts4-3 "${testcvs} -q co -l first-dir" '' - cd ../1/first-dir - echo baseline >file1 - dotest conflicts4-4 "${testcvs} -q add file1" \ -"$PROG add: use .$PROG commit. to add this file permanently" - dotest conflicts4-5 "${testcvs} -q ci -m add-it" \ -"RCS file: $CVSROOT_DIRNAME/first-dir/file1,v -done -Checking in file1; -$CVSROOT_DIRNAME/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - cd ../../2/first-dir - dotest conflicts4-6 "${testcvs} -q update" "U file1" - # Make a local change - echo wibble2 >> file1 - dotest conflicts4-7 "${testcvs} -q ci -m update2" \ -"Checking in file1; -$CVSROOT_DIRNAME/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../../1/first-dir - echo wibble1 >>file1 - dotest conflicts4-8 "${testcvs} -Q update" \ -"RCS file: $CVSROOT_DIRNAME/first-dir/file1,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into file1 -rcsmerge: warning: conflicts during merge -cvs update: conflicts found in file1" - dotest_fail conflicts4-9 "${testcvs} -q update" \ -"C file1" - - if $remote; then - cat >$TESTDIR/conflicts4/serveme <<EOF -#!$TESTSHELL -# This is admittedly a bit cheezy, in the sense that we make lots -# of assumptions about what the client is going to send us. -# We don't mention Repository, because current clients don't require it. -# Sending these at our own pace, rather than waiting for the client to -# make the requests, is bogus, but hopefully we can get away with it. -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update Global_option" -echo "ok" -echo "MT text C " -echo "MT fname file1" -echo "MT newline" -echo "error " -cat >$TESTDIR/conflicts4/client.out -EOF - # Cygwin. Pthffffffffft! - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod +x $TESTDIR/conflicts4/serveme" - else - chmod +x $TESTDIR/conflicts4/serveme - fi - save_CVS_SERVER=$CVS_SERVER - CVS_SERVER=$TESTDIR/conflicts4/serveme; export CVS_SERVER - dotest_fail conflicts4-10r "$testcvs -q up" "C file1" - dotest conflicts4-11r "cat $TESTDIR/conflicts4/client.out" \ -"$DOTSTAR -Argument -- -Directory . -$CVSROOT_DIRNAME/first-dir -Entry /file1/1.2/$PLUS=// -Modified file1 -u=.*,g=.*,o=.* -59 -baseline -""<<<<<<< file1 -wibble1 -""======= -wibble2 -"">>>>>>> 1.2 -update" - - cat >$TESTDIR/conflicts4/serveme <<EOF -#!$TESTSHELL -# This is admittedly a bit cheezy, in the sense that we make lots -# of assumptions about what the client is going to send us. -# We don't mention Repository, because current clients don't require it. -# Sending these at our own pace, rather than waiting for the client to -# make the requests, is bogus, but hopefully we can get away with it. -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update Global_option Empty-conflicts" -echo "ok" -echo "MT text C " -echo "MT fname file1" -echo "MT newline" -echo "error " -cat >$TESTDIR/conflicts4/client.out -EOF - - dotest_fail conflicts4-12r "$testcvs -q up" "C file1" - dotest conflicts4-13r "cat $TESTDIR/conflicts4/client.out" \ -"$DOTSTAR -Argument -- -Directory . -$CVSROOT_DIRNAME/first-dir -Entry /file1/1.2/$PLUS=// -Unchanged file1 -update" - - CVS_SERVER=$save_CVS_SERVER; export CVS_SERVER - fi - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd ../../.. - rm -rf conflicts4 - 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 ${CVSROOT_DIRNAME}/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} add: scheduling file .cleanme\.txt. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest clean-4 "${testcvs} -q ci -m clean-3" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/cleanme\.txt,v -done -Checking in cleanme\.txt; -${CVSROOT_DIRNAME}/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" - - # Now try with conflicts - cd .. - dotest clean-15 "${testcvs} -q co -d second-dir first-dir" \ -'U second-dir/cleanme\.txt' - cd second-dir - echo "conflict test" >> cleanme.txt - dotest clean-16 "${testcvs} -q ci -m." \ -"Checking in cleanme\.txt; -${CVSROOT_DIRNAME}/first-dir/cleanme\.txt,v <-- cleanme\.txt -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../first-dir - echo "fish" >> cleanme.txt - dotest clean-17 "${testcvs} -nq update" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/cleanme\.txt,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into cleanme\.txt -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in cleanme\.txt -C cleanme\.txt" - dotest clean-18 "${testcvs} -q update -C" \ -"(Locally modified cleanme\.txt moved to \.#cleanme\.txt\.1\.1) -U cleanme\.txt" - dotest clean-19 "cat .#cleanme.txt.1.1" \ -"The usual boring test text\. -fish" - - # Done. Clean up. - cd ../.. - rm -rf 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - modules) - # Tests of various ways to define and use modules. - # Roadmap to various modules tests: - # -a: - # error on incorrect placement: modules - # error combining with other options: modules2-a* - # infinite loops: modules148a1.1 - modules148a1.2 - # use to specify a file more than once: modules3 - # use with ! feature: modules4 - # regular modules: modules, modules2, cvsadm - # ampersand modules: modules2 - # -s: modules. - # -d: modules, modules3, cvsadm - # -i, -o, -u, -e, -t: modules5 - # slashes in module names: modules3 - # invalid module definitions: modules6 - - ############################################################ - # These tests are to make sure that administrative files get - # rebuilt, regardless of how and where files are checked - # out. - ############################################################ - # Check out the whole repository - mkdir 1; cd 1 - dotest modules-1 "${testcvs} -q co ." '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' - echo "# made a change" >>CVSROOT/modules - dotest modules-1d "${testcvs} -q ci -m add-modules" \ -"Checking in CVSROOT/modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd .. - rm -rf 1 - - ############################################################ - # Check out CVSROOT - mkdir 1; cd 1 - dotest modules-2 "${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' - echo "# made a change" >>CVSROOT/modules - dotest modules-2d "${testcvs} -q ci -m add-modules" \ -"Checking in CVSROOT/modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd .. - rm -rf 1 - - ############################################################ - # Check out CVSROOT in some other directory - mkdir ${CVSROOT_DIRNAME}/somedir - mkdir 1; cd 1 - dotest modules-3 "${testcvs} -q co somedir" '' - cd somedir - dotest modules-3d "${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' - echo "# made a change" >>CVSROOT/modules - dotest modules-3g "${testcvs} -q ci -m add-modules" \ -"Checking in CVSROOT/modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../.. - rm -rf 1 - rm -rf ${CVSROOT_DIRNAME}/somedir - ############################################################ - # end rebuild tests - ############################################################ - - - mkdir ${CVSROOT_DIRNAME}/first-dir - - mkdir 1 - cd 1 - - dotest modules-143 "${testcvs} -q co first-dir" "" - - cd first-dir - mkdir subdir - dotest modules-143a "${testcvs} add subdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository" - - cd subdir - mkdir ssdir - dotest modules-143b "${testcvs} add ssdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/subdir/ssdir added to the repository" - - touch a b - - dotest modules-144 "${testcvs} add a b" \ -"${PROG} add: scheduling file .a. for addition -${PROG} add: scheduling file .b. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - - dotest modules-145 "${testcvs} ci -m added" \ -"${PROG} [a-z]*: Examining . -${PROG} [a-z]*: Examining ssdir -RCS file: ${CVSROOT_DIRNAME}/first-dir/subdir/a,v -done -Checking in a; -${CVSROOT_DIRNAME}/first-dir/subdir/a,v <-- a -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/subdir/b,v -done -Checking in b; -${CVSROOT_DIRNAME}/first-dir/subdir/b,v <-- b -initial revision: 1\.1 -done" - - cd .. - 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. - dotest modules-147 "${testcvs} -q update" "" - - cat >CVSROOT/modules <<EOF -realmodule first-dir/subdir a -dirmodule first-dir/subdir -namedmodule -d nameddir first-dir/subdir -aliasmodule -a first-dir/subdir/a -aliasnested -a first-dir/subdir/ssdir -topfiles -a first-dir/file1 first-dir/file2 -world -a . -statusmod -s Mungeable -# Check for ability to block infinite loops. -infinitealias -a infinitealias -# Prior to 1.11.12 & 1.12.6, the infinite alias loop check didn't strip -# slashes or work if a module called a module which then called itself -# (A -> A was blocked, but not A -> B -> A or deeper). -infinitealias2 -a infinitealias2/ -infinitealias3 -a infinitealias4/ -infinitealias4 -a aliasmodule infinitealias5 -infinitealias5 -a infinitealias3/ -# 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. -bogusalias first-dir/subdir/a -a -EOF - dotest modules-148 "${testcvs} ci -m 'add modules' CVSROOT/modules" \ -"Checking in CVSROOT/modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - - 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 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 -infinitealias -a infinitealias -infinitealias2 -a infinitealias2/ -infinitealias3 -a infinitealias4/ -infinitealias4 -a aliasmodule infinitealias5 -infinitealias5 -a infinitealias3/ -namedmodule -d nameddir first-dir/subdir -realmodule first-dir/subdir a -statusmod -s Mungeable -topfiles -a first-dir/file1 first-dir/file2 -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 modules-148a1 "${testcvs} co -s" \ -'statusmod Mungeable -bogusalias NONE first-dir/subdir/a -a -dirmodule NONE first-dir/subdir -namedmodule NONE first-dir/subdir -realmodule NONE first-dir/subdir a' - - # Check that infinite loops are avoided - dotest modules-148a1.1 "${testcvs} co infinitealias" \ -"$PROG checkout: module \`infinitealias' in modules file contains infinite loop" \ -"$PROG server: module \`infinitealias' in modules file contains infinite loop -$PROG checkout: module \`infinitealias' in modules file contains infinite loop" - # Prior to 1.11.12 & 1.12.6, the inifinte alias loop check did not - # strip slashes. - dotest modules-148a1.2 "${testcvs} co infinitealias2" \ -"$PROG checkout: module \`infinitealias2' in modules file contains infinite loop" \ -"$PROG server: module \`infinitealias2' in modules file contains infinite loop -$PROG checkout: module \`infinitealias2' in modules file contains infinite loop" - # Prior to 1.11.12 & 1.12.6, the inifinte alias loop check did not - # notice when A -> B -> A, it only noticed A -> A. - dotest modules-148a1.3 "${testcvs} co infinitealias3/" \ -"$PROG checkout: module \`infinitealias3' in modules file contains infinite loop" \ -"$PROG server: module \`infinitealias3' in modules file contains infinite loop -$PROG checkout: module \`infinitealias3' in modules file contains infinite loop" - - # Test that real modules check out to realmodule/a, not subdir/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}"' checkout: module `realmodule/a'\'' is a request for a file in a module which is not a directory' \ -"${PROG}"' server: module `realmodule/a'\'' is a request for a file in a module which is not a directory -'"${PROG}"' \[checkout aborted\]: cannot expand modules' - - # Now test the ability to check out a single file from a directory - 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. - # 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} checkout: 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. - 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 modules-150h1 "${testcvs} -q co namedmodule" \ -'U nameddir/a -U nameddir/b' - dotest modules-150h2 "test -f nameddir/a && test -f nameddir/b" "" - echo add line >>nameddir/a - dotest modules-150h3 "${testcvs} -q co namedmodule" 'M nameddir/a' - rm nameddir/a - 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. - dotest modules-151 "${testcvs} co aliasmodule" "" - dotest_fail modules-152 "test -d aliasmodule" "" - echo abc >>first-dir/subdir/a - dotest modules-153 "${testcvs} -q co aliasmodule" "M first-dir/subdir/a" - - cd .. - rm -r 1 - - mkdir 2 - cd 2 - dotest modules-155a0 "${testcvs} co aliasnested" \ -"${PROG} checkout: Updating first-dir/subdir/ssdir" - dotest modules-155a1 "test -d first-dir" '' - dotest modules-155a2 "test -d first-dir/subdir" '' - dotest modules-155a3 "test -d first-dir/subdir/ssdir" '' - # Test that nothing extraneous got created. - dotest modules-155a4 "ls" "first-dir" \ -"CVS -first-dir" - cd .. - rm -r 2 - - # Test checking out everything. - mkdir 1 - cd 1 - dotest modules-155b "${testcvs} -q co world" \ -"U CVSROOT/${DOTSTAR} -U first-dir/subdir/a -U first-dir/subdir/b" - cd .. - rm -r 1 - - # Test checking out a module which lists at least two - # specific files twice. At one time, this failed over - # remote CVS. - mkdir 1 - cd 1 - dotest modules-155c1 "${testcvs} -q co first-dir" \ -"U first-dir/subdir/a -U first-dir/subdir/b" - - cd first-dir - echo 'first revision' > file1 - echo 'first revision' > file2 - dotest modules-155c2 "${testcvs} add file1 file2" \ -"${PROG}"' add: scheduling file `file1'\'' for addition -'"${PROG}"' add: scheduling file `file2'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add these files permanently' - dotest modules-155c3 "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - - cd .. - rm -r first-dir - dotest modules-155c4 "${testcvs} -q co topfiles" \ -"U first-dir/file1 -U first-dir/file2" - dotest modules-155c5 "${testcvs} -q co topfiles" "" - - # Make sure the right thing happens if we remove a file. - cd first-dir - dotest modules-155c6 "${testcvs} -q rm -f file1" \ -"${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest modules-155c7 "${testcvs} -q ci -m remove-it" \ -"Removing file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done" - cd .. - rm -r first-dir - dotest modules-155c8 "${testcvs} -q co topfiles" \ -"${PROG} checkout: warning: first-dir/file1 is not (any longer) pertinent -U first-dir/file2" - - cd .. - rm -r 1 - - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - modules2) - # More tests of modules, in particular the & feature. - mkdir 1; cd 1 - dotest modules2-setup-1 "${testcvs} -q co -l ." '' - mkdir first-dir second-dir third-dir - dotest modules2-setup-2 \ -"${testcvs} add first-dir second-dir third-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository -Directory ${CVSROOT_DIRNAME}/second-dir added to the repository -Directory ${CVSROOT_DIRNAME}/third-dir added to the repository" - cd third-dir - touch file3 - dotest modules2-setup-3 "${testcvs} add file3" \ -"${PROG} add: scheduling file .file3. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest modules2-setup-4 "${testcvs} -q ci -m add file3" \ -"RCS file: ${CVSROOT_DIRNAME}/third-dir/file3,v -done -Checking in file3; -${CVSROOT_DIRNAME}/third-dir/file3,v <-- file3 -initial revision: 1\.1 -done" - cd ../.. - rm -r 1 - - mkdir 1 - cd 1 - - dotest modules2-1 "${testcvs} -q co CVSROOT/modules" \ -'U CVSROOT/modules' - cd CVSROOT - cat >> modules << EOF -ampermodule &first-dir &second-dir -combmodule third-dir file3 &first-dir -ampdirmod -d newdir &first-dir &second-dir -badmod -d newdir -messymod first-dir &messymodchild -messymodchild -d sdir/child second-dir -EOF - # 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" \ -"Checking in modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - - cd .. - - dotest modules2-3 "${testcvs} -q co ampermodule" '' - dotest modules2-4 "test -d ampermodule/first-dir" '' - dotest modules2-5 "test -d ampermodule/second-dir" '' - - # Test ability of cvs release to handle multiple arguments - # See comment at "release" for list of other cvs release tests. - cd ampermodule - if ${testcvs} release -d first-dir second-dir <<EOF >>${LOGFILE} -yes -yes -EOF - then - pass modules2-6 - else - fail modules2-6 - fi - dotest_fail modules2-7 "test -d first-dir" '' - dotest_fail modules2-8 "test -d second-dir" '' - - cd .. - - # There used to be a nasty-hack that made CVS skip creation of the - # module dir (in this case ampermodule) when -n was specified - dotest modules2-ampermod-1 "${testcvs} -q co -n ampermodule" '' - dotest modules2-ampermod-2 "test -d ampermodule/first-dir" '' - dotest modules2-ampermod-3 "test -d ampermodule/second-dir" '' - - # Test release of a module - if echo yes |${testcvs} release -d ampermodule >>${LOGFILE}; then - pass modules2-ampermod-release-1 - else - fail modules2-ampermod-release-1 - fi - dotest_fail modules2-ampermod-release-2 "test -d ampermodule" '' - - # and the '-n' test again, but in conjunction with '-d' - dotest modules2-ampermod-4 "${testcvs} -q co -n -d newname ampermodule" '' - dotest modules2-ampermod-5 "test -d newname/first-dir" '' - dotest modules2-ampermod-6 "test -d newname/second-dir" '' - rm -rf newname - - # Now we create another directory named first-dir and make - # sure that CVS doesn't get them mixed up. - mkdir first-dir - # Note that this message should say "Updating ampermodule/first-dir" - # I suspect. This is a long-standing behavior/bug.... - dotest modules2-9 "${testcvs} co ampermodule" \ -"${PROG} checkout: Updating first-dir -${PROG} checkout: Updating second-dir" - touch ampermodule/first-dir/amper1 - cd ampermodule - dotest modules2-10 "${testcvs} add first-dir/amper1" \ -"${PROG} add: scheduling file .first-dir/amper1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - cd .. - - # As with the "Updating xxx" message, the "U first-dir/amper1" - # message (instead of "U ampermodule/first-dir/amper1") is - # rather fishy. - dotest modules2-12 "${testcvs} co ampermodule" \ -"${PROG} checkout: Updating first-dir -A first-dir/amper1 -${PROG} checkout: Updating second-dir" - - if $remote; then - dotest modules2-13 "${testcvs} -q ci -m add-it ampermodule" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/amper1,v -done -Checking in ampermodule/first-dir/amper1; -${CVSROOT_DIRNAME}/first-dir/amper1,v <-- amper1 -initial revision: 1\.1 -done" - else - # Trying this as above led to a "protocol error" message. - # Work around this bug. - cd ampermodule - dotest modules2-13 "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/amper1,v -done -Checking in first-dir/amper1; -${CVSROOT_DIRNAME}/first-dir/amper1,v <-- amper1 -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). - mkdir 1; cd 1 - dotest modules2-14 "${testcvs} co combmodule" \ -"U combmodule/file3 -${PROG} checkout: Updating first-dir -U first-dir/amper1" - dotest modules2-15 "test -f combmodule/file3" "" - dotest modules2-16 "test -f combmodule/first-dir/amper1" "" - cd combmodule - rm -r first-dir - # At least for now there is no way to tell CVS that - # some files/subdirectories come from one repository directory, - # and others from another. - # This seems like a pretty sensible behavior to me, in the - # sense that first-dir doesn't "really" exist within - # third-dir, so CVS just acts as if there is nothing there - # to do. - dotest modules2-17 "${testcvs} update -d" \ -"${PROG} update: Updating \." - - cd .. - dotest modules2-18 "${testcvs} -q co combmodule" \ -"U first-dir/amper1" - dotest modules2-19 "test -f combmodule/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} checkout: Updating first-dir -U first-dir/amper1 -${PROG} checkout: Updating second-dir" - dotest modules2-21 "test -f newdir/first-dir/amper1" "" - dotest modules2-22 "test -d newdir/second-dir" "" - dotest_fail modules2-23 "${testcvs} co badmod" \ -"${PROG} checkout: modules file missing directory for module badmod" \ -"${PROG} server: modules file missing directory for module badmod -${PROG} \[checkout aborted\]: cannot expand modules" - cd .. - rm -r 1 - - # Confirm that a rename with added depth nested in an ampersand - # module works. - mkdir 1; cd 1 - dotest modules2-nestedrename-1 "${testcvs} -q co messymod" \ -"U messymod/amper1" - dotest modules2-nestedrename-2 "test -d messymod/sdir" '' - dotest modules2-nestedrename-3 "test -d messymod/sdir/CVS" '' - dotest modules2-nestedrename-4 "test -d messymod/sdir/child" '' - dotest modules2-nestedrename-5 "test -d messymod/sdir/child/CVS" '' - cd ..; rm -r 1 - - # FIXME: client/server has a bug. It should be working like a local - # repository in this case, but fails to check out the second module - # in the list when a branch is specified. - mkdir 1; cd 1 - dotest modules2-ampertag-setup-1 \ -"${testcvs} -Q rtag tag first-dir second-dir third-dir" \ -'' - dotest modules2-ampertag-1 "${testcvs} -q co -rtag ampermodule" \ -"U first-dir/amper1" - if $remote; then - dotest_fail modules2-ampertag-2 "test -d ampermodule/second-dir" '' - dotest_fail modules2-ampertag-3 "test -d ampermodule/second-dir/CVS" '' - else - dotest modules2-ampertag-2 "test -d ampermodule/second-dir" '' - dotest modules2-ampertag-3 "test -d ampermodule/second-dir/CVS" '' - fi - cd ..; rm -r 1 - - # Test for tag files when an ampermod is renamed with more path - # elements than it started with. - # - # FIXME: This is currently broken in the remote case, possibly only - # because the messymodchild isn't being checked out at all. - mkdir 1; cd 1 -# dotest modules2-tagfiles-setup-1 \ -#"${testcvs} -Q rtag -b branch first-dir second-dir" \ -#'' - dotest modules2-tagfiles-1 "${testcvs} -q co -rtag messymod" \ -"U messymod/amper1" - if $remote; then - dotest_fail modules2-tagfiles-2r "test -d messymod/sdir" '' - else - dotest modules2-tagfiles-2 "cat messymod/sdir/CVS/Tag" 'Ttag' - fi - 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 - # test. Although it is short, it shares no files/state with - # the rest of the modules2 tests. - mkdir 1; cd 1 - dotest modules2-a0.5 "${testcvs} -q co CVSROOT/modules" \ -'U CVSROOT/modules' - cd CVSROOT - echo 'aliasopt -a -d onedir first-dir' >modules - dotest modules2-a0 "${testcvs} -q ci -m add-modules" \ -"Checking in modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd .. - dotest_fail modules2-a1 "${testcvs} -q co aliasopt" \ -"${PROG} checkout: -a cannot be specified in the modules file along with other options" \ -"${PROG} server: -a cannot be specified in the modules file along with other options -${PROG} \[checkout aborted\]: cannot expand modules" - cd ..; rm -r 1 - - # Clean up. - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -rf ${CVSROOT_DIRNAME}/second-dir - rm -rf ${CVSROOT_DIRNAME}/third-dir - ;; - - modules3) - # More tests of modules, in particular what happens if several - # modules point to the same file. - - # First just set up a directory first-dir and a file file1 in it. - mkdir 1; cd 1 - - dotest modules3-0 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest modules3-1 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - - cd first-dir - echo file1 >file1 - dotest modules3-2 "${testcvs} add file1" \ -"${PROG} add: scheduling file \`file1' for addition -${PROG} add: use '${PROG} commit' to add this file permanently" - dotest modules3-3 "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - cd .. - - dotest modules3-4 "${testcvs} -q update -d CVSROOT" \ -"U CVSROOT${DOTSTAR}" - cd CVSROOT - cat >modules <<EOF -mod1 -a first-dir/file1 -bigmod -a mod1 first-dir/file1 -namednest -d src/sub/dir first-dir -nestdeeper -d src/sub1/sub2/sub3/dir first-dir -nestshallow -d src/dir second-dir/suba/subb -path/in/modules &mod1 -another/path/test -d another/path/test first-dir -EOF - dotest modules3-5 "${testcvs} -q ci -m add-modules" \ -"Checking in modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd .. - - dotest modules3-6 "${testcvs} -q co bigmod" '' - rm -r first-dir - dotest modules3-7 "${testcvs} -q co bigmod" 'U first-dir/file1' - cd .. - rm -r 1 - - mkdir 1; cd 1 - mkdir suba - mkdir suba/subb - # This fails to work remote (it doesn't notice the directories, - # I suppose because they contain no files). Bummer, especially - # considering this is a documented technique and everything. - dotest modules3-7a \ -"${testcvs} import -m add-dirs second-dir tag1 tag2" \ -"${PROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/suba -${PROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/suba/subb - -No conflicts created by this import" " -No conflicts created by this import" - cd ..; rm -r 1 - mkdir 1; cd 1 - dotest modules3-7b "${testcvs} co second-dir" \ -"${PROG} checkout: Updating second-dir -${PROG} checkout: Updating second-dir/suba -${PROG} checkout: Updating second-dir/suba/subb" \ -"${PROG} checkout: Updating second-dir" - - if $remote; then - cd second-dir - mkdir suba - dotest modules3-7-workaround1 "${testcvs} add suba" \ -"Directory ${CVSROOT_DIRNAME}/second-dir/suba added to the repository" - cd suba - mkdir subb - dotest modules3-7-workaround2 "${testcvs} add subb" \ -"Directory ${CVSROOT_DIRNAME}/second-dir/suba/subb added to the repository" - cd ../.. - fi - - cd second-dir/suba/subb - touch fileb - dotest modules3-7c "${testcvs} add fileb" \ -"${PROG} add: scheduling file .fileb. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest modules3-7d "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/second-dir/suba/subb/fileb,v -done -Checking in fileb; -${CVSROOT_DIRNAME}/second-dir/suba/subb/fileb,v <-- fileb -initial revision: 1\.1 -done" - cd ../../.. - cd ..; rm -r 1 - - mkdir 1 - cd 1 - dotest modules3-8 "${testcvs} -q co namednest" \ -'U src/sub/dir/file1' - dotest modules3-9 "test -f src/sub/dir/file1" '' - cd .. - rm -r 1 - - # Try the same thing, but with the directories nested even - # deeper (deeply enough so they are nested more deeply than - # the number of directories from / to ${TESTDIR}). - mkdir 1 - cd 1 - dotest modules3-10 "${testcvs} -q co nestdeeper" \ -'U src/sub1/sub2/sub3/dir/file1' - dotest modules3-11 "test -f src/sub1/sub2/sub3/dir/file1" '' - - # While we are doing things like twisted uses of '/' (e.g. - # modules3-12), try this one. - if $remote; then - dotest_fail modules3-11b \ -"${testcvs} -q update ${TESTDIR}/1/src/sub1/sub2/sub3/dir/file1" \ -"absolute pathname .${TESTDIR}/1/src/sub1/sub2/sub3/dir. illegal for server" - fi # end of remote-only tests - - cd .. - rm -r 1 - - # This one is almost too twisted for words. The pathname output - # in the message from "co" doesn't include the "path/in/modules", - # but those directories do get created (with no CVSADM except - # in "modules" which has a CVSNULLREPOS). - # I'm not sure anyone is relying on this nonsense or whether we - # need to keep doing it, but it is what CVS currently does... - # Skip it for remote; the remote code has the good sense to - # not deal with it (on the minus side it gives - # "internal error: repository string too short." (CVS 1.9) or - # "warning: server is not creating directories one at a time" (now) - # instead of a real error). - # I'm tempted to just make it a fatal error to have '/' in a - # module name. But see comments at modules3-16. - if $remote; then :; else - mkdir 1; cd 1 - dotest modules3-12 "${testcvs} -q co path/in/modules" \ -"U first-dir/file1" - dotest modules3-13 "test -f path/in/modules/first-dir/file1" '' - cd ..; rm -r 1 - fi # end of tests skipped for remote - - # Now here is where it used to get seriously bogus. - mkdir 1; cd 1 - dotest modules3-14 \ -"${testcvs} -q rtag tag1 path/in/modules" '' - # CVS used to create this even though rtag should *never* affect - # the directory current when it is called! - dotest_fail modules3-15 "test -d path/in/modules" '' - # Just for trivia's sake, rdiff was not similarly vulnerable - # because it passed 0 for run_module_prog to do_module. - cd ..; rm -r 1 - - # Some people seem to want this to work. I still suspect there - # are dark corners in slashes in module names. This probably wants - # more thought before we start hacking on CVS (one way or the other) - # or documenting this. - mkdir 2; cd 2 - dotest modules3-16 "${testcvs} -q co another/path/test" \ -"U another/path/test/file1" - dotest modules3-17 "cat another/path/test/file1" 'file1' - cd ..; rm -r 2 - - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -rf ${CVSROOT_DIRNAME}/second-dir - ;; - - modules4) - # Some tests using the modules file with aliases that - # exclude particular directories. - - mkdir 1; cd 1 - - dotest modules4-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest modules4-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - - cd first-dir - mkdir subdir subdir_long - dotest modules4-3 "${testcvs} add subdir subdir_long" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository -Directory ${CVSROOT_DIRNAME}/first-dir/subdir_long added to the repository" - - echo file1 > file1 - dotest modules4-4 "${testcvs} add file1" \ -"${PROG}"' add: scheduling file `file1'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - - echo file2 > subdir/file2 - dotest modules4-5 "${testcvs} add subdir/file2" \ -"${PROG}"' add: scheduling file `subdir/file2'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - - echo file3 > subdir_long/file3 - dotest modules4-6 "${testcvs} add subdir_long/file3" \ -"${PROG}"' add: scheduling file `subdir_long/file3'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - - dotest modules4-7 "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/subdir/file2,v -done -Checking in subdir/file2; -${CVSROOT_DIRNAME}/first-dir/subdir/file2,v <-- file2 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/subdir_long/file3,v -done -Checking in subdir_long/file3; -${CVSROOT_DIRNAME}/first-dir/subdir_long/file3,v <-- file3 -initial revision: 1\.1 -done" - - cd .. - - dotest modules4-8 "${testcvs} -q update -d CVSROOT" \ -"U CVSROOT${DOTSTAR}" - cd CVSROOT - cat >modules <<EOF -all -a first-dir -some -a !first-dir/subdir first-dir -other -a !first-dir/subdir !first-dir/subdir_long first-dir -somewhat -a first-dir !first-dir/subdir -EOF - dotest modules4-9 "${testcvs} -q ci -m add-modules" \ -"Checking in modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd .. - - cd .. - mkdir 2; cd 2 - - dotest modules4-10 "${testcvs} -q co all" \ -"U first-dir/file1 -U first-dir/subdir/file2 -U first-dir/subdir_long/file3" - rm -r first-dir - - dotest modules4-11 "${testcvs} -q co some" \ -"U first-dir/file1 -U first-dir/subdir_long/file3" - dotest_fail modules4-12 "test -d first-dir/subdir" '' - dotest modules4-13 "test -d first-dir/subdir_long" '' - rm -r first-dir - - if $remote; then - # But remote seems to do it the other way. - dotest modules4-14r-1 "${testcvs} -q co somewhat" \ -"U first-dir/file1 -U first-dir/subdir_long/file3" - dotest_fail modules4-14r-2 "test -d first-dir/subdir" '' - dotest modules4-14r-3 "test -d first-dir/subdir_long" '' - else - # This is strange behavior, in that the order of the - # "!first-dir/subdir" and "first-dir" matter, and it isn't - # clear that they should. I suspect it is long-standing - # strange behavior but I haven't verified that. - dotest modules4-14-1 "${testcvs} -q co somewhat" \ -"U first-dir/file1 -U first-dir/subdir/file2 -U first-dir/subdir_long/file3" - dotest modules4-14-2 "test -d first-dir/subdir" '' - dotest modules4-14-3 "test -d first-dir/subdir_long" '' - fi - rm -r first-dir - - dotest modules4-15 "${testcvs} -q co other" \ -"U first-dir/file1" - dotest_fail modules4-16 "test -d first-dir/subdir" '' - dotest_fail modules4-17 "test -d first-dir/subdir_long" '' - rm -r first-dir - - cd .. - rm -r 2 - - dotest modules4-18 "${testcvs} rtag tag some" \ -"${PROG} rtag: Tagging first-dir -${PROG} rtag: Ignoring first-dir/subdir -${PROG} rtag: Tagging first-dir/subdir_long" - - cd 1/first-dir/subdir - dotest modules4-19 "${testcvs} log file2" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/subdir/file2,v -Working file: file2 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -add-it -=============================================================================" - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd ../../.. - rm -r 1 - - 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 ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository" - cd subdir - mkdir ssdir - dotest modules5-3 "${testcvs} add ssdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/subdir/ssdir added to the repository" - touch a b - dotest modules5-4 "${testcvs} add a b" \ -"${PROG} add: scheduling file .a. for addition -${PROG} add: scheduling file .b. for addition -${PROG} add: 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: ${CVSROOT_DIRNAME}/first-dir/subdir/a,v -done -Checking in a; -${CVSROOT_DIRNAME}/first-dir/subdir/a,v <-- a -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/subdir/b,v -done -Checking in b; -${CVSROOT_DIRNAME}/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" - - # FIXCVS: The sleep in the following script helps avoid out of - # order messages, but we really need to figure out how to fix - # cvs to prevent them in the first place. - for i in checkout export tag; do - cat >> ${CVSROOT_DIRNAME}/$i.sh <<EOF -#! /bin/sh -sleep 1 -echo "$i script invoked in \`pwd\`" -echo "args: \$@" -EOF - # Cygwin doesn't set premissions correctly over the Samba share. - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod +x ${CVSROOT_DIRNAME}/$i.sh" - else - chmod +x ${CVSROOT_DIRNAME}/$i.sh - fi - done - - OPTS="-o${CVSROOT_DIRNAME}/checkout.sh -e ${CVSROOT_DIRNAME}/export.sh -t${CVSROOT_DIRNAME}/tag.sh" - cat >CVSROOT/modules <<EOF -realmodule ${OPTS} first-dir/subdir a -dirmodule ${OPTS} first-dir/subdir -namedmodule -d nameddir ${OPTS} first-dir/subdir -EOF - - dotest modules5-7 "${testcvs} ci -m 'add modules' CVSROOT/modules" \ -"" \ -"Checking in CVSROOT/modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - - cd .. - rm -rf first-dir - - # Test that real modules check out to realmodule/a, not subdir/a. - if $remote; then - # FIXCVS? - # Mac OSX 10.3 (Darwin ppc-osx1 5.5) fails here when $TMPDIR - # contains a symlink (it does not fail the local modules5-8). - # Since no other platforms are exhibiting the same problem, I - # suspect an issue with OSX and fork() or the like dereferencing - # the symlink, but it is possible it is something that could be - # fixed or worked around in CVS. - dotest modules5-8r "$testcvs co realmodule" \ -"U realmodule/a -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .realmodule.. -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: realmodule" - else - dotest modules5-8 "${testcvs} co realmodule" \ -"U realmodule/a -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .realmodule.. -checkout script invoked in ${TESTDIR}/1 -args: realmodule" - fi - dotest modules5-9 "test -d realmodule && test -f realmodule/a" "" - dotest_fail modules5-10 "test -f realmodule/b" "" - if $remote; then - dotest modules5-11 "${testcvs} -q co realmodule" \ -"checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: realmodule" - dotest modules5-12 "${testcvs} -q update" '' - 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" - else - dotest modules5-11 "${testcvs} -q co realmodule" \ -"checkout script invoked in ${TESTDIR}/1 -args: realmodule" - dotest modules5-12 "${testcvs} -q update" '' - 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" - 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" \ -"tag script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: realmodule MYTAG" - if $remote; then - dotest modules5-16 "${testcvs} -q export -r MYTAG realmodule" \ -"U realmodule/a -export script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: realmodule" - else - dotest modules5-16 "${testcvs} -q export -r MYTAG realmodule" \ -"U realmodule/a -export script invoked in ${TESTDIR}/1 -args: realmodule" - fi - rm -r realmodule - - dotest_fail modules5-17 "${testcvs} co realmodule/a" \ -"${PROG}"' checkout: module `realmodule/a'\'' is a request for a file in a module which is not a directory' \ -"${PROG}"' server: module `realmodule/a'\'' is a request for a file in a module which is not a directory -'"${PROG}"' \[checkout aborted\]: cannot expand modules' - - # Now test the ability to check out a single file from a directory - if $remote; then - dotest modules5-18 "${testcvs} co dirmodule/a" \ -"U dirmodule/a -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule.. -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: dirmodule" - else - dotest modules5-18 "${testcvs} co dirmodule/a" \ -"U dirmodule/a -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule.. -checkout script invoked in ${TESTDIR}/1 -args: dirmodule" - fi - 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. - if $remote; then - dotest modules5-22 "${testcvs} co dirmodule/nonexist" \ -"${PROG} checkout: warning: new-born dirmodule/nonexist has disappeared -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule.. -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: dirmodule" - else - dotest modules5-22 "${testcvs} co dirmodule/nonexist" \ -"${PROG} checkout: warning: new-born dirmodule/nonexist has disappeared -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule.. -checkout script invoked in ${TESTDIR}/1 -args: dirmodule" - fi - # 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. - if $remote; then - dotest modules5-24 "${testcvs} -q co namedmodule" \ -"U nameddir/a -U nameddir/b -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: nameddir" - else - dotest modules5-24 "${testcvs} -q co namedmodule" \ -"U nameddir/a -U nameddir/b -checkout script invoked in ${TESTDIR}/1 -args: nameddir" - fi - 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? - if $remote; then - dotest modules5-26 "${testcvs} -q co namedmodule" \ -"M nameddir/a -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: nameddir" - else - dotest modules5-26 "${testcvs} -q co namedmodule" \ -"M nameddir/a -checkout script invoked in ${TESTDIR}/1 -args: nameddir" - fi - rm nameddir/a - - if $remote; then - dotest modules5-27 "${testcvs} -q co namedmodule" \ -"U nameddir/a -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: nameddir" - else - dotest modules5-27 "${testcvs} -q co namedmodule" \ -"U nameddir/a -checkout script invoked in ${TESTDIR}/1 -args: nameddir" - fi - 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.: " - - # Now try the same tests with -d on command line - # FIXCVS? The manual says the modules programs get the module name, - # but they really get the directory name. - if $remote; then - dotest modules5-29 "${testcvs} co -d mydir realmodule" \ -"U mydir/a -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir.. -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: mydir" - else - dotest modules5-29 "${testcvs} co -d mydir realmodule" \ -"U mydir/a -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir.. -checkout script invoked in ${TESTDIR}/1 -args: mydir" - fi - dotest modules5-30 "test -d mydir && test -f mydir/a" "" - dotest_fail modules5-31 "test -d realmodule || test -f mydir/b" "" - if $remote; then - dotest modules5-32 "${testcvs} -q co -d mydir realmodule" \ -"checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: mydir" - dotest modules5-33 "${testcvs} -q update" '' - echo "change" >>mydir/a - dotest modules5-34 "${testcvs} -q ci -m." \ -"Checking in mydir/a; -${CVSROOT_DIRNAME}/first-dir/subdir/a,v <-- a -new revision: 1\.3; previous revision: 1\.2 -done" - else - dotest modules5-32 "${testcvs} -q co -d mydir realmodule" \ -"checkout script invoked in ${TESTDIR}/1 -args: mydir" - dotest modules5-33 "${testcvs} -q update" '' - echo "change" >>mydir/a - dotest modules5-34 "${testcvs} -q ci -m." \ -"Checking in mydir/a; -${CVSROOT_DIRNAME}/first-dir/subdir/a,v <-- a -new revision: 1\.3; previous revision: 1\.2 -done" - fi - dotest modules5-35 "echo yes | ${testcvs} release -d mydir" \ -"You have \[0\] altered files in this repository\. -Are you sure you want to release (and delete) directory .mydir.: " - if $remote; then - dotest modules5-36 "${testcvs} -q rtag -Dnow MYTAG2 realmodule" \ -"tag script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: realmodule MYTAG2" - dotest modules5-37 "${testcvs} -q export -r MYTAG2 -d mydir realmodule" \ -"U mydir/a -export script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: mydir" - else - dotest modules5-36 "${testcvs} -q rtag -Dnow MYTAG2 realmodule" \ -"tag script invoked in ${TESTDIR}/1 -args: realmodule MYTAG2" - dotest modules5-37 "${testcvs} -q export -r MYTAG2 -d mydir realmodule" \ -"U mydir/a -export script invoked in ${TESTDIR}/1 -args: mydir" - fi - rm -r mydir - - # Now test the ability to check out a single file from a directory - if $remote; then - dotest modules5-38 "${testcvs} co -d mydir dirmodule/a" \ -"U mydir/a -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir.. -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: mydir" - else - dotest modules5-38 "${testcvs} co -d mydir dirmodule/a" \ -"U mydir/a -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir.. -checkout script invoked in ${TESTDIR}/1 -args: mydir" - fi - dotest modules5-39 "test -d mydir && test -f mydir/a" "" - dotest_fail modules5-40 "test -d dirmodule || test -f mydir/b" "" - dotest modules5-41 "echo yes | ${testcvs} release -d mydir" \ -"You have \[0\] altered files in this repository\. -Are you sure you want to release (and delete) directory .mydir.: " - - # 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. - if $remote; then - dotest modules5-42 "${testcvs} co -d mydir dirmodule/nonexist" \ -"${PROG} checkout: warning: new-born mydir/nonexist has disappeared -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir.. -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: mydir" - else - dotest modules5-42 "${testcvs} co -d mydir dirmodule/nonexist" \ -"${PROG} checkout: warning: new-born mydir/nonexist has disappeared -${PROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir.. -checkout script invoked in ${TESTDIR}/1 -args: mydir" - fi - # We tolerate the creation of the mydir directory, since that - # is what CVS does, not because we view that as preferable to not - # creating it. - dotest_fail modules5-43 "test -f mydir/a || test -f mydir/b" "" - rm -r mydir - - if $remote; then - dotest modules5-44 "${testcvs} -q co -d mydir namedmodule" \ -"U mydir/a -U mydir/b -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: mydir" - else - dotest modules5-44 "${testcvs} -q co -d mydir namedmodule" \ -"U mydir/a -U mydir/b -checkout script invoked in ${TESTDIR}/1 -args: mydir" - fi - dotest modules5-45 "test -f mydir/a && test -f mydir/b" "" - dotest_fail modules5-46 "test -d namedir" - echo add line >>mydir/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? - if $remote; then - dotest modules5-47 "${testcvs} -q co -d mydir namedmodule" \ -"M mydir/a -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: mydir" - else - dotest modules5-47 "${testcvs} -q co -d mydir namedmodule" \ -"M mydir/a -checkout script invoked in ${TESTDIR}/1 -args: mydir" - fi - rm mydir/a - - if $remote; then - dotest modules5-48 "${testcvs} -q co -d mydir namedmodule" \ -"U mydir/a -checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]* -args: mydir" - else - dotest modules5-48 "${testcvs} -q co -d mydir namedmodule" \ -"U mydir/a -checkout script invoked in ${TESTDIR}/1 -args: mydir" - fi - dotest modules5-49 "echo yes | ${testcvs} release -d mydir" \ -"You have \[0\] altered files in this repository\. -Are you sure you want to release (and delete) directory .mydir.: " - - cd .. - rm -rf 1 ${CVSROOT_DIRNAME}/first-dir ${CVSROOT_DIRNAME}/*.sh - ;; - - modules6) - # - # Test invalid module definitions - # - # See the header comment for the `modules' test for an index of - # the complete suite of modules tests. - # - - # - # There was a bug in CVS through 1.11.1p1 where a bad module name - # would cause the previous line to be parsed as the module - # definition. This test proves this doesn't happen anymore. - # - mkdir modules6 - cd modules6 - dotest module6-setup-1 "${testcvs} -Q co CVSROOT" "" - cd CVSROOT - echo "longmodulename who cares" >modules - echo "badname" >>modules - # This test almost isn't setup since it generates the error message - # we are looking for if `-Q' isn't specified, but I want to test the - # filename in the message later. - dotest modules6-setup-2 "${testcvs} -Q ci -mbad-modules" \ -"Checking in modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: [0-9.]*; previous revision: [0-9.]* -done -${PROG} commit: Rebuilding administrative file database" - - # Here's where CVS would report not being able to find `lename' - cd .. - dotest_fail modules6-1 "${testcvs} -q co badname" \ -"${PROG} checkout: warning: NULL value for key .badname. at line 2 of .${CVSROOT_DIRNAME}/CVSROOT/modules. -${PROG} checkout: cannot find module .badname. - ignored" \ -"${PROG} server: warning: NULL value for key .badname. at line 2 of .${CVSROOT_DIRNAME}/CVSROOT/modules. -${PROG} server: cannot find module .badname. - ignored -${PROG} \[checkout aborted\]: cannot expand modules" - - # cleanup - cd CVSROOT - echo "# empty modules file" >modules - dotest modules6-cleanup-1 "${testcvs} -Q ci -mempty-modules" \ -"Checking in modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: [0-9.]*; previous revision: [0-9.]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../.. - - if $keep; then :; else - rm -r modules6 - fi - ;; - - - - modules7) - # - # Test tag problems vs an empty CVSROOT/val-tags file - # - # See the header comment for the `modules' test for an index of - # the complete suite of modules tests. - # - mkdir modules7 - cd modules7 - dotest modules7-1 "$testcvs -Q co -d top ." - cd top - mkdir zero one - dotest modules7-2 "$testcvs -Q add zero one" - cd one - echo 'file1 contents' > file1 - dotest modules7-2 "$testcvs -Q add file1" - dotest modules7-3 "$testcvs -Q ci -mnew file1" \ -"RCS file: $CVSROOT_DIRNAME/one/file1,v -done -Checking in file1; -$CVSROOT_DIRNAME/one/file1,v <-- file1 -initial revision: 1\.1 -done" - dotest modules7-4 "$testcvs -Q tag mytag file1" - cd ../CVSROOT - echo 'all -a zero one' > modules - dotest modules7-5 "$testcvs -Q ci -mall-module" \ -"Checking in modules; -$CVSROOT_DIRNAME/CVSROOT/modules,v <-- modules -new revision: [0-9.]*; previous revision: [0-9.]* -done -$PROG commit: Rebuilding administrative file database" - cd ../.. - mkdir myexport - cd myexport - # FIXCVS: The export should NOT be aborted here - dotest_fail modules7-6 "$testcvs export -rmytag all" \ -"$PROG \[export aborted\]: no such tag mytag" - cd .. - rm -fr myexport - mkdir myexport - cd myexport - # FIXCVS: Workaround is to have mytag listed in val-tags - echo 'mytag y' > $CVSROOT_DIRNAME/CVSROOT/val-tags - dotest modules7-7 "$testcvs export -rmytag all" \ -"$PROG export: Updating zero -$PROG export: Updating one -U one/file1" - dotest modules7-8 'cat one/file1' 'file1 contents' - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - # cleanup - cd ../top/CVSROOT - echo "# empty modules file" >modules - dotest modules7-cleanup-1 "$testcvs -Q ci -mempty-modules" \ -"Checking in modules; -$CVSROOT_DIRNAME/CVSROOT/modules,v <-- modules -new revision: [0-9.]*; previous revision: [0-9.]* -done -$PROG commit: Rebuilding administrative file database" - cd ../../.. - rm -fr modules7 - rm -rf $CVSROOT_DIRNAME/zero $CVSROOT_DIRNAME/one - ;; - - - mkmodules) - # When a file listed in checkoutlist doesn't exist, cvs-1.10.4 - # would fail to remove the CVSROOT/.#[0-9]* temporary file it - # creates while mkmodules is in the process of trying to check - # out the missing file. - - mkdir 1; cd 1 - dotest mkmodules-temp-file-removal-1 "${testcvs} -Q co CVSROOT" '' - cd CVSROOT - echo no-such-file >> checkoutlist - dotest mkmodules-temp-file-removal-2 "${testcvs} -Q ci -m. checkoutlist" \ -"Checking in checkoutlist; -$CVSROOT_DIRNAME/CVSROOT/checkoutlist,v <-- checkoutlist -new revision: 1\.2; previous revision: 1\.1 -done -${PROG} commit: Rebuilding administrative file database" - - dotest mkmodules-temp-file-removal-3 "echo $CVSROOT_DIRNAME/CVSROOT/.#[0-9]*" \ - "$CVSROOT_DIRNAME/CVSROOT/\.#\[0-9\]\*" - - # Versions 1.11.6 & 1.12.1 and earlier of CVS printed most of the - # white space included before error messages in checkoutlist. - echo "no-such-file Failed to update no-such-file." >checkoutlist - dotest mkmodules-error-message-1 "${testcvs} -Q ci -m. checkoutlist" \ -"Checking in checkoutlist; -$CVSROOT_DIRNAME/CVSROOT/checkoutlist,v <-- checkoutlist -new revision: 1\.3; previous revision: 1\.2 -done -${PROG} commit: Rebuilding administrative file database -${PROG} commit: Failed to update no-such-file\." - - # Versions 1.11.6 & 1.12.1 and earlier of CVS used the error string - # from the checkoutlist file as the format string passed to error()'s - # printf. Check that this is no longer the case by verifying that - # printf format patterns remain unchanged. - echo "no-such-file Failed to update %s %lx times because %s happened %d times." >checkoutlist - dotest mkmodules-error-message-2 "${testcvs} -Q ci -m. checkoutlist" \ -"Checking in checkoutlist; -$CVSROOT_DIRNAME/CVSROOT/checkoutlist,v <-- checkoutlist -new revision: 1\.4; previous revision: 1\.3 -done -${PROG} commit: Rebuilding administrative file database -${PROG} commit: Failed to update %s %lx times because %s happened %d times\." - - dotest mkmodules-cleanup-1 "${testcvs} -Q up -pr1.1 checkoutlist >checkoutlist" - dotest mkmodules-cleanup-2 "${testcvs} -Q ci -m. checkoutlist" \ -"Checking in checkoutlist; -$CVSROOT_DIRNAME/CVSROOT/checkoutlist,v <-- checkoutlist -new revision: 1\.5; previous revision: 1\.4 -done -${PROG} commit: Rebuilding administrative file database" - - cd ../.. - rm -rf 1 - ;; - - co-d) - # Some tests of various permutations of co-d when directories exist - # and checkouts lengthen. - # - # Interestingly enough, these same tests pass when the directory - # lengthening happens via the modules file. Go figure. - module=co-d - mkdir $module; cd $module - mkdir top; cd top - dotest co-d-init-1 "$testcvs -Q co -l ." - mkdir $module - dotest co-d-init-2 "$testcvs -Q add $module" - cd $module - echo content >file1 - echo different content >file2 - dotest co-d-init-3 "$testcvs -Q add file1 file2" - dotest co-d-init-4 "$testcvs -Q ci -madd-em" \ -"RCS file: $CVSROOT_DIRNAME/co-d/file1,v -done -Checking in file1; -$CVSROOT_DIRNAME/co-d/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: $CVSROOT_DIRNAME/co-d/file2,v -done -Checking in file2; -$CVSROOT_DIRNAME/co-d/file2,v <-- file2 -initial revision: 1\.1 -done" - cd ../.. - - mkdir 2; cd 2 - dotest co-d-1 "$testcvs -q co -d dir $module" \ -"U dir/file1 -U dir/file2" - dotest co-d-1.2 "cat dir/CVS/Repository" "$module" - - # FIXCVS: This should work. Correct expected result: - # - #"U dir2/sdir/file1 - #U dir2/sdir/file2" - dotest_fail co-d-2 "$testcvs -q co -d dir2/sdir $module" \ -"$PROG \[checkout aborted\]: could not change directory to requested checkout directory \`dir2': No such file or directory" - # FIXCVS: - # dotest co-d-2.2 "cat dir4/CVS/Repository" "CVSROOT/Emptydir" - # dotest co-d-2.3 "cat dir5/CVS/Repository" "$module" - - mkdir dir3 - dotest co-d-3 "$testcvs -q co -d dir3 $module" \ -"U dir3/file1 -U dir3/file2" - dotest co-d-3.2 "cat dir3/CVS/Repository" "$module" - - if $remote; then - # FIXCVS: As for co-d-2. - mkdir dir4 - dotest_fail co-d-4r "$testcvs -q co -d dir4/sdir $module" \ -"$PROG \[checkout aborted\]: could not change directory to requested checkout directory \`dir4': No such file or directory" - - # FIXCVS: As for co-d-2. - mkdir dir5 - mkdir dir5/sdir - dotest_fail co-d-5r "$testcvs -q co -d dir5/sdir $module" \ -"$PROG \[checkout aborted\]: could not change directory to requested checkout directory \`dir5': No such file or directory" - else - mkdir dir4 - dotest co-d-4 "$testcvs -q co -d dir4/sdir $module" \ -"U dir4/sdir/file1 -U dir4/sdir/file2" - # CVS only creates administration directories for directories it - # creates, and the last portion of the path passed to -d - # regardless. - dotest_fail co-d-4.2 "test -d dir4/CVS" - dotest co-d-4.3 "cat dir4/sdir/CVS/Repository" "$module" - - mkdir dir5 - mkdir dir5/sdir - dotest co-d-5 "$testcvs -q co -d dir5/sdir $module" \ -"U dir5/sdir/file1 -U dir5/sdir/file2" - # CVS only creates administration directories for directories it - # creates, and the last portion of the path passed to -d - # regardless. - dotest_fail co-d-5.2 "test -d dir5/CVS" - dotest co-d-5.3 "cat dir5/sdir/CVS/Repository" "$module" - fi - - # clean up - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd ../.. - rm -rf $CVSROOT_DIRNAME/$module - rm -r $module - ;; - - cvsadm) - # These test check the content of CVS' administrative - # files as they are checked out in various configurations. - # (As a side note, I'm not using the "-q" flag in any of - # this code, which should provide some extra checking for - # those messages which don't seem to be checked thoroughly - # anywhere else.) To do a thorough test, we need to make - # a bunch of modules in various configurations. - # - # <1mod> is a directory at the top level of cvsroot - # ``foo bar'' - # <2mod> is a directory at the second level of cvsroot - # ``foo bar/baz'' - # <1d1mod> is a directory at the top level which is - # checked out into another directory - # ``foo -d bar baz'' - # <1d2mod> is a directory at the second level which is - # checked out into another directory - # ``foo -d bar baz/quux'' - # <2d1mod> is a directory at the top level which is - # checked out into a directory that is two deep - # ``foo -d bar/baz quux'' - # <2d2mod> is a directory at the second level which is - # checked out into a directory that is two deep - # ``foo -d bar/baz quux'' - # - # The tests do each of these types separately and in twos. - # We also repeat each test -d flag for 1-deep and 2-deep - # directories. - # - # Each test should check the output for the Repository - # file, since that is the one which varies depending on - # the directory and how it was checked out. - # - # Yes, this is verbose, but at least it's very thorough. - - # convenience variables - REP=${CVSROOT} - - # First, set TopLevelAdmin=yes so we're sure to get - # top-level CVS directories. - mkdir 1; cd 1 - dotest cvsadm-setup-1 "${testcvs} -q co CVSROOT/config" \ -"U CVSROOT/config" - cd CVSROOT - echo "TopLevelAdmin=yes" >config - dotest cvsadm-setup-2 "${testcvs} -q ci -m yes-top-level" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../.. - rm -r 1 - - # Second, check out the modules file and edit it. - mkdir 1; cd 1 - dotest cvsadm-1 "${testcvs} co CVSROOT/modules" \ -"U CVSROOT/modules" - - # Test CVS/Root once. Since there is only one part of - # the code which writes CVS/Root files (Create_Admin), - # there is no point in testing this every time. - dotest cvsadm-1a "cat CVS/Root" ${REP} - dotest cvsadm-1b "cat CVS/Repository" "\." - dotest cvsadm-1c "cat CVSROOT/CVS/Root" ${REP} - dotest cvsadm-1d "cat CVSROOT/CVS/Repository" "CVSROOT" - # All of the defined module names begin with a number. - # All of the top-level directory names begin with "dir". - # All of the subdirectory names begin with "sub". - # All of the top-level modules begin with "mod". - echo "# Module defs for cvsadm tests" > CVSROOT/modules - echo "1mod mod1" >> CVSROOT/modules - echo "1mod-2 mod1-2" >> CVSROOT/modules - echo "2mod mod2/sub2" >> CVSROOT/modules - echo "2mod-2 mod2-2/sub2-2" >> CVSROOT/modules - echo "1d1mod -d dir1d1 mod1" >> CVSROOT/modules - echo "1d1mod-2 -d dir1d1-2 mod1-2" >> CVSROOT/modules - echo "1d2mod -d dir1d2 mod2/sub2" >> CVSROOT/modules - echo "1d2mod-2 -d dir1d2-2 mod2-2/sub2-2" >> CVSROOT/modules - echo "2d1mod -d dir2d1/sub2d1 mod1" >> CVSROOT/modules - echo "2d1mod-2 -d dir2d1-2/sub2d1-2 mod1-2" >> CVSROOT/modules - echo "2d2mod -d dir2d2/sub2d2 mod2/sub2" >> CVSROOT/modules - echo "2d2mod-2 -d dir2d2-2/sub2d2-2 mod2-2/sub2-2" >> CVSROOT/modules - dotest cvsadm-1e "${testcvs} ci -m add-modules" \ -"${PROG} [a-z]*: Examining . -${PROG} [a-z]*: Examining CVSROOT -Checking in CVSROOT/modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" \ -"${PROG} commit: Examining . -${PROG} commit: Examining CVSROOT" - rm -rf CVS CVSROOT; - - # Create the various modules - dotest cvsadm-2 "${testcvs} -q co -l ." '' - mkdir mod1 - mkdir mod1-2 - mkdir mod2 - mkdir mod2/sub2 - mkdir mod2-2 - mkdir mod2-2/sub2-2 - dotest cvsadm-2a "${testcvs} add mod1 mod1-2 mod2 mod2/sub2 mod2-2 mod2-2/sub2-2" \ -"Directory ${CVSROOT_DIRNAME}/mod1 added to the repository -Directory ${CVSROOT_DIRNAME}/mod1-2 added to the repository -Directory ${CVSROOT_DIRNAME}/mod2 added to the repository -Directory ${CVSROOT_DIRNAME}/mod2/sub2 added to the repository -Directory ${CVSROOT_DIRNAME}/mod2-2 added to the repository -Directory ${CVSROOT_DIRNAME}/mod2-2/sub2-2 added to the repository" - - # Populate the directories for the halibut - echo "file1" > mod1/file1 - echo "file1-2" > mod1-2/file1-2 - echo "file2" > mod2/sub2/file2 - echo "file2-2" > mod2-2/sub2-2/file2-2 - dotest cvsadm-2aa "${testcvs} add mod1/file1 mod1-2/file1-2 mod2/sub2/file2 mod2-2/sub2-2/file2-2" \ -"${PROG} add: scheduling file .mod1/file1. for addition -${PROG} add: scheduling file .mod1-2/file1-2. for addition -${PROG} add: scheduling file .mod2/sub2/file2. for addition -${PROG} add: scheduling file .mod2-2/sub2-2/file2-2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - - dotest cvsadm-2b "${testcvs} ci -m yup mod1 mod1-2 mod2 mod2-2" \ -"${PROG} [a-z]*: Examining mod1 -${PROG} [a-z]*: Examining mod1-2 -${PROG} [a-z]*: Examining mod2 -${PROG} [a-z]*: Examining mod2/sub2 -${PROG} [a-z]*: Examining mod2-2 -${PROG} [a-z]*: Examining mod2-2/sub2-2 -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}/mod1-2/file1-2,v -done -Checking in mod1-2/file1-2; -${CVSROOT_DIRNAME}/mod1-2/file1-2,v <-- file1-2 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/mod2/sub2/file2,v -done -Checking in mod2/sub2/file2; -${CVSROOT_DIRNAME}/mod2/sub2/file2,v <-- file2 -initial revision: 1.1 -done -RCS file: ${CVSROOT_DIRNAME}/mod2-2/sub2-2/file2-2,v -done -Checking in mod2-2/sub2-2/file2-2; -${CVSROOT_DIRNAME}/mod2-2/sub2-2/file2-2,v <-- file2-2 -initial revision: 1.1 -done" - # Finished creating the modules -- clean up. - rm -rf CVS mod1 mod1-2 mod2 mod2-2 - # Done. - - ################################################## - ## Start the dizzying array of possibilities. - ## Begin with each module type separately. - ################################################## - - # Pattern -- after each checkout, first check the top-level - # CVS directory. Then, check the directories in numerical - # order. - - dotest cvsadm-3 "${testcvs} co 1mod" \ -"${PROG} checkout: Updating 1mod -U 1mod/file1" - dotest cvsadm-3b "cat CVS/Repository" "\." - dotest cvsadm-3d "cat 1mod/CVS/Repository" "mod1" - rm -rf CVS 1mod - - dotest cvsadm-4 "${testcvs} co 2mod" \ -"${PROG} checkout: Updating 2mod -U 2mod/file2" - dotest cvsadm-4b "cat CVS/Repository" "\." - dotest cvsadm-4d "cat 2mod/CVS/Repository" "mod2/sub2" - rm -rf CVS 2mod - - dotest cvsadm-5 "${testcvs} co 1d1mod" \ -"${PROG} checkout: Updating dir1d1 -U dir1d1/file1" - dotest cvsadm-5b "cat CVS/Repository" "\." - dotest cvsadm-5d "cat dir1d1/CVS/Repository" "mod1" - rm -rf CVS dir1d1 - - dotest cvsadm-6 "${testcvs} co 1d2mod" \ -"${PROG} checkout: Updating dir1d2 -U dir1d2/file2" - dotest cvsadm-6b "cat CVS/Repository" "\." - dotest cvsadm-6d "cat dir1d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir1d2 - - dotest cvsadm-7 "${testcvs} co 2d1mod" \ -"${PROG} checkout: Updating dir2d1/sub2d1 -U dir2d1/sub2d1/file1" - dotest cvsadm-7b "cat CVS/Repository" "\." - dotest cvsadm-7d "cat dir2d1/CVS/Repository" "\." - dotest cvsadm-7f "cat dir2d1/sub2d1/CVS/Repository" "mod1" - rm -rf CVS dir2d1 - - dotest cvsadm-8 "${testcvs} co 2d2mod" \ -"${PROG} checkout: Updating dir2d2/sub2d2 -U dir2d2/sub2d2/file2" - dotest cvsadm-8b "cat CVS/Repository" "\." - dotest cvsadm-8d "cat dir2d2/CVS/Repository" "mod2" - dotest cvsadm-8f "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir2d2 - - ################################################## - ## You are in a shell script of twisted little - ## module combination statements, all alike. - ################################################## - - ### 1mod - - dotest cvsadm-9 "${testcvs} co 1mod 1mod-2" \ -"${PROG} checkout: Updating 1mod -U 1mod/file1 -${PROG} checkout: Updating 1mod-2 -U 1mod-2/file1-2" - # the usual for the top level - dotest cvsadm-9b "cat CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-9d "cat 1mod/CVS/Repository" "mod1" - # the usual for 1mod copy - dotest cvsadm-9f "cat 1mod-2/CVS/Repository" "mod1-2" - rm -rf CVS 1mod 1mod-2 - - # 1mod 2mod redmod bluemod - dotest cvsadm-10 "${testcvs} co 1mod 2mod" \ -"${PROG} checkout: Updating 1mod -U 1mod/file1 -${PROG} checkout: Updating 2mod -U 2mod/file2" - # the usual for the top level - dotest cvsadm-10b "cat CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-10d "cat 1mod/CVS/Repository" "mod1" - # the usual for 2dmod - dotest cvsadm-10f "cat 2mod/CVS/Repository" "mod2/sub2" - rm -rf CVS 1mod 2mod - - dotest cvsadm-11 "${testcvs} co 1mod 1d1mod" \ -"${PROG} checkout: Updating 1mod -U 1mod/file1 -${PROG} checkout: Updating dir1d1 -U dir1d1/file1" - # the usual for the top level - dotest cvsadm-11b "cat CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-11d "cat 1mod/CVS/Repository" "mod1" - # the usual for 1d1mod - dotest cvsadm-11f "cat dir1d1/CVS/Repository" "mod1" - rm -rf CVS 1mod dir1d1 - - dotest cvsadm-12 "${testcvs} co 1mod 1d2mod" \ -"${PROG} checkout: Updating 1mod -U 1mod/file1 -${PROG} checkout: Updating dir1d2 -U dir1d2/file2" - # the usual for the top level - dotest cvsadm-12b "cat CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-12d "cat 1mod/CVS/Repository" "mod1" - # the usual for 1d2mod - dotest cvsadm-12f "cat dir1d2/CVS/Repository" "mod2/sub2" - rm -rf CVS 1mod dir1d2 - - dotest cvsadm-13 "${testcvs} co 1mod 2d1mod" \ -"${PROG} checkout: Updating 1mod -U 1mod/file1 -${PROG} checkout: Updating dir2d1/sub2d1 -U dir2d1/sub2d1/file1" - # the usual for the top level - dotest cvsadm-13b "cat CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-13d "cat 1mod/CVS/Repository" "mod1" - # the usual for 2d1mod - dotest cvsadm-13f "cat dir2d1/CVS/Repository" "\." - dotest cvsadm-13h "cat dir2d1/sub2d1/CVS/Repository" "mod1" - rm -rf CVS 1mod dir2d1 - - dotest cvsadm-14 "${testcvs} co 1mod 2d2mod" \ -"${PROG} checkout: Updating 1mod -U 1mod/file1 -${PROG} checkout: Updating dir2d2/sub2d2 -U dir2d2/sub2d2/file2" - # the usual for the top level - dotest cvsadm-14b "cat CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-14d "cat 1mod/CVS/Repository" "mod1" - # the usual for 2d2mod - dotest cvsadm-14f "cat dir2d2/CVS/Repository" "mod2" - dotest cvsadm-14h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS 1mod dir2d2 - - - ### 2mod - - dotest cvsadm-15 "${testcvs} co 2mod 2mod-2" \ -"${PROG} checkout: Updating 2mod -U 2mod/file2 -${PROG} checkout: Updating 2mod-2 -U 2mod-2/file2-2" - # the usual for the top level - dotest cvsadm-15b "cat CVS/Repository" "\." - # the usual for 2mod - dotest cvsadm-15d "cat 2mod/CVS/Repository" "mod2/sub2" - # the usual for 2mod copy - dotest cvsadm-15f "cat 2mod-2/CVS/Repository" "mod2-2/sub2-2" - rm -rf CVS 2mod 2mod-2 - - - dotest cvsadm-16 "${testcvs} co 2mod 1d1mod" \ -"${PROG} checkout: Updating 2mod -U 2mod/file2 -${PROG} checkout: Updating dir1d1 -U dir1d1/file1" - # the usual for the top level - dotest cvsadm-16b "cat CVS/Repository" "\." - # the usual for 2mod - dotest cvsadm-16d "cat 2mod/CVS/Repository" "mod2/sub2" - # the usual for 1d1mod - dotest cvsadm-16f "cat dir1d1/CVS/Repository" "mod1" - rm -rf CVS 2mod dir1d1 - - dotest cvsadm-17 "${testcvs} co 2mod 1d2mod" \ -"${PROG} checkout: Updating 2mod -U 2mod/file2 -${PROG} checkout: Updating dir1d2 -U dir1d2/file2" - # the usual for the top level - dotest cvsadm-17b "cat CVS/Repository" "\." - # the usual for 2mod - dotest cvsadm-17d "cat 2mod/CVS/Repository" "mod2/sub2" - # the usual for 1d2mod - dotest cvsadm-17f "cat dir1d2/CVS/Repository" "mod2/sub2" - rm -rf CVS 2mod dir1d2 - - dotest cvsadm-18 "${testcvs} co 2mod 2d1mod" \ -"${PROG} checkout: Updating 2mod -U 2mod/file2 -${PROG} checkout: Updating dir2d1/sub2d1 -U dir2d1/sub2d1/file1" - # the usual for the top level - dotest cvsadm-18b "cat CVS/Repository" "\." - # the usual for 2mod - dotest cvsadm-18d "cat 2mod/CVS/Repository" "mod2/sub2" - # the usual for 2d1mod - dotest cvsadm-18f "cat dir2d1/CVS/Repository" "\." - dotest cvsadm-18h "cat dir2d1/sub2d1/CVS/Repository" "mod1" - rm -rf CVS 2mod dir2d1 - - dotest cvsadm-19 "${testcvs} co 2mod 2d2mod" \ -"${PROG} checkout: Updating 2mod -U 2mod/file2 -${PROG} checkout: Updating dir2d2/sub2d2 -U dir2d2/sub2d2/file2" - # the usual for the top level - dotest cvsadm-19b "cat CVS/Repository" "\." - # the usual for 2mod - dotest cvsadm-19d "cat 2mod/CVS/Repository" "mod2/sub2" - # the usual for 2d2mod - dotest cvsadm-19f "cat dir2d2/CVS/Repository" "mod2" - dotest cvsadm-19h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS 2mod dir2d2 - - - ### 1d1mod - - dotest cvsadm-20 "${testcvs} co 1d1mod 1d1mod-2" \ -"${PROG} checkout: Updating dir1d1 -U dir1d1/file1 -${PROG} checkout: Updating dir1d1-2 -U dir1d1-2/file1-2" - # the usual for the top level - dotest cvsadm-20b "cat CVS/Repository" "\." - # the usual for 1d1mod - dotest cvsadm-20d "cat dir1d1/CVS/Repository" "mod1" - # the usual for 1d1mod copy - dotest cvsadm-20f "cat dir1d1-2/CVS/Repository" "mod1-2" - rm -rf CVS dir1d1 dir1d1-2 - - dotest cvsadm-21 "${testcvs} co 1d1mod 1d2mod" \ -"${PROG} checkout: Updating dir1d1 -U dir1d1/file1 -${PROG} checkout: Updating dir1d2 -U dir1d2/file2" - # the usual for the top level - dotest cvsadm-21b "cat CVS/Repository" "\." - # the usual for 1d1mod - dotest cvsadm-21d "cat dir1d1/CVS/Repository" "mod1" - # the usual for 1d2mod - dotest cvsadm-21f "cat dir1d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir1d1 dir1d2 - - dotest cvsadm-22 "${testcvs} co 1d1mod 2d1mod" \ -"${PROG} checkout: Updating dir1d1 -U dir1d1/file1 -${PROG} checkout: Updating dir2d1/sub2d1 -U dir2d1/sub2d1/file1" - # the usual for the top level - dotest cvsadm-22b "cat CVS/Repository" "\." - # the usual for 1d1mod - dotest cvsadm-22d "cat dir1d1/CVS/Repository" "mod1" - # the usual for 2d1mod - dotest cvsadm-22f "cat dir2d1/CVS/Repository" "\." - dotest cvsadm-22h "cat dir2d1/sub2d1/CVS/Repository" "mod1" - rm -rf CVS dir1d1 dir2d1 - - dotest cvsadm-23 "${testcvs} co 1d1mod 2d2mod" \ -"${PROG} checkout: Updating dir1d1 -U dir1d1/file1 -${PROG} checkout: Updating dir2d2/sub2d2 -U dir2d2/sub2d2/file2" - # the usual for the top level - dotest cvsadm-23b "cat CVS/Repository" "\." - # the usual for 1d1mod - dotest cvsadm-23d "cat dir1d1/CVS/Repository" "mod1" - # the usual for 2d2mod - dotest cvsadm-23f "cat dir2d2/CVS/Repository" "mod2" - dotest cvsadm-23h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir1d1 dir2d2 - - - ### 1d2mod - - dotest cvsadm-24 "${testcvs} co 1d2mod 1d2mod-2" \ -"${PROG} checkout: Updating dir1d2 -U dir1d2/file2 -${PROG} checkout: Updating dir1d2-2 -U dir1d2-2/file2-2" - # the usual for the top level - dotest cvsadm-24b "cat CVS/Repository" "\." - # the usual for 1d2mod - dotest cvsadm-24d "cat dir1d2/CVS/Repository" "mod2/sub2" - # the usual for 1d2mod copy - dotest cvsadm-24f "cat dir1d2-2/CVS/Repository" "mod2-2/sub2-2" - rm -rf CVS dir1d2 dir1d2-2 - - dotest cvsadm-25 "${testcvs} co 1d2mod 2d1mod" \ -"${PROG} checkout: Updating dir1d2 -U dir1d2/file2 -${PROG} checkout: Updating dir2d1/sub2d1 -U dir2d1/sub2d1/file1" - # the usual for the top level - dotest cvsadm-25b "cat CVS/Repository" "\." - # the usual for 1d2mod - dotest cvsadm-25d "cat dir1d2/CVS/Repository" "mod2/sub2" - # the usual for 2d1mod - dotest cvsadm-25f "cat dir2d1/CVS/Repository" "\." - dotest cvsadm-25h "cat dir2d1/sub2d1/CVS/Repository" "mod1" - rm -rf CVS dir1d2 dir2d1 - - dotest cvsadm-26 "${testcvs} co 1d2mod 2d2mod" \ -"${PROG} checkout: Updating dir1d2 -U dir1d2/file2 -${PROG} checkout: Updating dir2d2/sub2d2 -U dir2d2/sub2d2/file2" - # the usual for the top level - dotest cvsadm-26b "cat CVS/Repository" "\." - # the usual for 1d2mod - dotest cvsadm-26d "cat dir1d2/CVS/Repository" "mod2/sub2" - # the usual for 2d2mod - dotest cvsadm-26f "cat dir2d2/CVS/Repository" "mod2" - dotest cvsadm-26h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir1d2 dir2d2 - - - # 2d1mod - - dotest cvsadm-27 "${testcvs} co 2d1mod 2d1mod-2" \ -"${PROG} checkout: Updating dir2d1/sub2d1 -U dir2d1/sub2d1/file1 -${PROG} checkout: Updating dir2d1-2/sub2d1-2 -U dir2d1-2/sub2d1-2/file1-2" - # the usual for the top level - dotest cvsadm-27b "cat CVS/Repository" "\." - # the usual for 2d1mod - dotest cvsadm-27d "cat dir2d1/CVS/Repository" "\." - dotest cvsadm-27f "cat dir2d1/sub2d1/CVS/Repository" "mod1" - # the usual for 2d1mod - dotest cvsadm-27h "cat dir2d1-2/CVS/Repository" "\." - dotest cvsadm-27j "cat dir2d1-2/sub2d1-2/CVS/Repository" "mod1-2" - rm -rf CVS dir2d1 dir2d1-2 - - dotest cvsadm-28 "${testcvs} co 2d1mod 2d2mod" \ -"${PROG} checkout: Updating dir2d1/sub2d1 -U dir2d1/sub2d1/file1 -${PROG} checkout: Updating dir2d2/sub2d2 -U dir2d2/sub2d2/file2" - # the usual for the top level - dotest cvsadm-28b "cat CVS/Repository" "\." - # the usual for 2d1mod - dotest cvsadm-28d "cat dir2d1/CVS/Repository" "\." - dotest cvsadm-28f "cat dir2d1/sub2d1/CVS/Repository" "mod1" - # the usual for 2d2mod - dotest cvsadm-28h "cat dir2d2/CVS/Repository" "mod2" - dotest cvsadm-28j "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir2d1 dir2d2 - - - # 2d2mod - - dotest cvsadm-29 "${testcvs} co 2d2mod 2d2mod-2" \ -"${PROG} checkout: Updating dir2d2/sub2d2 -U dir2d2/sub2d2/file2 -${PROG} checkout: Updating dir2d2-2/sub2d2-2 -U dir2d2-2/sub2d2-2/file2-2" - # the usual for the top level - dotest cvsadm-29b "cat CVS/Repository" "\." - # the usual for 2d2mod - dotest cvsadm-29d "cat dir2d2/CVS/Repository" "mod2" - dotest cvsadm-29f "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - # the usual for 2d2mod - dotest cvsadm-29h "cat dir2d2-2/CVS/Repository" "mod2-2" - dotest cvsadm-29j "cat dir2d2-2/sub2d2-2/CVS/Repository" \ -"mod2-2/sub2-2" - rm -rf CVS dir2d2 dir2d2-2 - - ################################################## - ## And now, all of that again using the "-d" flag - ## on the command line. - ################################################## - - dotest cvsadm-1d3 "${testcvs} co -d dir 1mod" \ -"${PROG} checkout: Updating dir -U dir/file1" - dotest cvsadm-1d3b "cat CVS/Repository" "\." - dotest cvsadm-1d3d "cat dir/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-1d4 "${testcvs} co -d dir 2mod" \ -"${PROG} checkout: Updating dir -U dir/file2" - dotest cvsadm-1d4b "cat CVS/Repository" "\." - dotest cvsadm-1d4d "cat dir/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - dotest cvsadm-1d5 "${testcvs} co -d dir 1d1mod" \ -"${PROG} checkout: Updating dir -U dir/file1" - dotest cvsadm-1d5b "cat CVS/Repository" "\." - dotest cvsadm-1d5d "cat dir/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-1d6 "${testcvs} co -d dir 1d2mod" \ -"${PROG} checkout: Updating dir -U dir/file2" - dotest cvsadm-1d6b "cat CVS/Repository" "\." - dotest cvsadm-1d6d "cat dir/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - dotest cvsadm-1d7 "${testcvs} co -d dir 2d1mod" \ -"${PROG} checkout: Updating dir -U dir/file1" - dotest cvsadm-1d7b "cat CVS/Repository" "\." - dotest cvsadm-1d7d "cat dir/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-1d8 "${testcvs} co -d dir 2d2mod" \ -"${PROG} checkout: Updating dir -U dir/file2" - dotest cvsadm-1d8b "cat CVS/Repository" "\." - dotest cvsadm-1d8d "cat dir/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - ################################################## - ## Los Combonaciones - ################################################## - - ### 1mod - - dotest cvsadm-1d9 "${testcvs} co -d dir 1mod 1mod-2" \ -"${PROG} checkout: Updating dir/1mod -U dir/1mod/file1 -${PROG} checkout: Updating dir/1mod-2 -U dir/1mod-2/file1-2" - # the usual for the top level - dotest cvsadm-1d9b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d9d "cat dir/CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-1d9f "cat dir/1mod/CVS/Repository" "mod1" - # the usual for 1mod copy - dotest cvsadm-1d9h "cat dir/1mod-2/CVS/Repository" "mod1-2" - rm -rf CVS dir - - # 1mod 2mod redmod bluemod - dotest cvsadm-1d10 "${testcvs} co -d dir 1mod 2mod" \ -"${PROG} checkout: Updating dir/1mod -U dir/1mod/file1 -${PROG} checkout: Updating dir/2mod -U dir/2mod/file2" - dotest cvsadm-1d10b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d10d "cat dir/CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-1d10f "cat dir/1mod/CVS/Repository" "mod1" - # the usual for 2dmod - dotest cvsadm-1d10h "cat dir/2mod/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - dotest cvsadm-1d11 "${testcvs} co -d dir 1mod 1d1mod" \ -"${PROG} checkout: Updating dir/1mod -U dir/1mod/file1 -${PROG} checkout: Updating dir/dir1d1 -U dir/dir1d1/file1" - dotest cvsadm-1d11b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d11d "cat dir/CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-1d11f "cat dir/1mod/CVS/Repository" "mod1" - # the usual for 1d1mod - dotest cvsadm-1d11h "cat dir/dir1d1/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-1d12 "${testcvs} co -d dir 1mod 1d2mod" \ -"${PROG} checkout: Updating dir/1mod -U dir/1mod/file1 -${PROG} checkout: Updating dir/dir1d2 -U dir/dir1d2/file2" - dotest cvsadm-1d12b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d12d "cat dir/CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-1d12f "cat dir/1mod/CVS/Repository" "mod1" - # the usual for 1d2mod - dotest cvsadm-1d12h "cat dir/dir1d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - dotest cvsadm-1d13 "${testcvs} co -d dir 1mod 2d1mod" \ -"${PROG} checkout: Updating dir/1mod -U dir/1mod/file1 -${PROG} checkout: Updating dir/dir2d1/sub2d1 -U dir/dir2d1/sub2d1/file1" - dotest cvsadm-1d13b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d13d "cat dir/CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-1d13f "cat dir/1mod/CVS/Repository" "mod1" - # the usual for 2d1mod - dotest cvsadm-1d13h "cat dir/dir2d1/CVS/Repository" "\." - dotest cvsadm-1d13j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-1d14 "${testcvs} co -d dir 1mod 2d2mod" \ -"${PROG} checkout: Updating dir/1mod -U dir/1mod/file1 -${PROG} checkout: Updating dir/dir2d2/sub2d2 -U dir/dir2d2/sub2d2/file2" - dotest cvsadm-1d14b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d14d "cat dir/CVS/Repository" "\." - # the usual for 1mod - dotest cvsadm-1d14f "cat dir/1mod/CVS/Repository" "mod1" - # the usual for 2d2mod - dotest cvsadm-1d14h "cat dir/dir2d2/CVS/Repository" "mod2" - dotest cvsadm-1d14j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - - ### 2mod - - dotest cvsadm-1d15 "${testcvs} co -d dir 2mod 2mod-2" \ -"${PROG} checkout: Updating dir/2mod -U dir/2mod/file2 -${PROG} checkout: Updating dir/2mod-2 -U dir/2mod-2/file2-2" - dotest cvsadm-1d15b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d15d "cat dir/CVS/Repository" "mod2" - # the usual for 2mod - dotest cvsadm-1d15f "cat dir/2mod/CVS/Repository" "mod2/sub2" - # the usual for 2mod copy - dotest cvsadm-1d15h "cat dir/2mod-2/CVS/Repository" "mod2-2/sub2-2" - rm -rf CVS dir - - dotest cvsadm-1d16 "${testcvs} co -d dir 2mod 1d1mod" \ -"${PROG} checkout: Updating dir/2mod -U dir/2mod/file2 -${PROG} checkout: Updating dir/dir1d1 -U dir/dir1d1/file1" - dotest cvsadm-1d16b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d16d "cat dir/CVS/Repository" "mod2" - # the usual for 2mod - dotest cvsadm-1d16f "cat dir/2mod/CVS/Repository" "mod2/sub2" - # the usual for 1d1mod - dotest cvsadm-1d16h "cat dir/dir1d1/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-1d17 "${testcvs} co -d dir 2mod 1d2mod" \ -"${PROG} checkout: Updating dir/2mod -U dir/2mod/file2 -${PROG} checkout: Updating dir/dir1d2 -U dir/dir1d2/file2" - dotest cvsadm-1d17b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d17d "cat dir/CVS/Repository" "mod2" - # the usual for 2mod - dotest cvsadm-1d17f "cat dir/2mod/CVS/Repository" "mod2/sub2" - # the usual for 1d2mod - dotest cvsadm-1d17h "cat dir/dir1d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - dotest cvsadm-1d18 "${testcvs} co -d dir 2mod 2d1mod" \ -"${PROG} checkout: Updating dir/2mod -U dir/2mod/file2 -${PROG} checkout: Updating dir/dir2d1/sub2d1 -U dir/dir2d1/sub2d1/file1" - dotest cvsadm-1d18b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d18d "cat dir/CVS/Repository" "mod2" - # the usual for 2mod - dotest cvsadm-1d18f "cat dir/2mod/CVS/Repository" "mod2/sub2" - # the usual for 2d1mod - dotest cvsadm-1d18h "cat dir/dir2d1/CVS/Repository" "\." - dotest cvsadm-1d18j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-1d19 "${testcvs} co -d dir 2mod 2d2mod" \ -"${PROG} checkout: Updating dir/2mod -U dir/2mod/file2 -${PROG} checkout: Updating dir/dir2d2/sub2d2 -U dir/dir2d2/sub2d2/file2" - dotest cvsadm-1d19b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d19d "cat dir/CVS/Repository" "mod2" - # the usual for 2mod - dotest cvsadm-1d19f "cat dir/2mod/CVS/Repository" "mod2/sub2" - # the usual for 2d2mod - dotest cvsadm-1d19h "cat dir/dir2d2/CVS/Repository" "mod2" - dotest cvsadm-1d19j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - - ### 1d1mod - - dotest cvsadm-1d20 "${testcvs} co -d dir 1d1mod 1d1mod-2" \ -"${PROG} checkout: Updating dir/dir1d1 -U dir/dir1d1/file1 -${PROG} checkout: Updating dir/dir1d1-2 -U dir/dir1d1-2/file1-2" - dotest cvsadm-1d20b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d20d "cat dir/CVS/Repository" "\." - # the usual for 1d1mod - dotest cvsadm-1d20f "cat dir/dir1d1/CVS/Repository" "mod1" - # the usual for 1d1mod copy - dotest cvsadm-1d20h "cat dir/dir1d1-2/CVS/Repository" "mod1-2" - rm -rf CVS dir - - dotest cvsadm-1d21 "${testcvs} co -d dir 1d1mod 1d2mod" \ -"${PROG} checkout: Updating dir/dir1d1 -U dir/dir1d1/file1 -${PROG} checkout: Updating dir/dir1d2 -U dir/dir1d2/file2" - dotest cvsadm-1d21b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d21d "cat dir/CVS/Repository" "\." - # the usual for 1d1mod - dotest cvsadm-1d21f "cat dir/dir1d1/CVS/Repository" "mod1" - # the usual for 1d2mod - dotest cvsadm-1d21h "cat dir/dir1d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - dotest cvsadm-1d22 "${testcvs} co -d dir 1d1mod 2d1mod" \ -"${PROG} checkout: Updating dir/dir1d1 -U dir/dir1d1/file1 -${PROG} checkout: Updating dir/dir2d1/sub2d1 -U dir/dir2d1/sub2d1/file1" - dotest cvsadm-1d22b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d22d "cat dir/CVS/Repository" "\." - # the usual for 1d1mod - dotest cvsadm-1d22f "cat dir/dir1d1/CVS/Repository" "mod1" - # the usual for 2d1mod - dotest cvsadm-1d22h "cat dir/dir2d1/CVS/Repository" "\." - dotest cvsadm-1d22j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-1d23 "${testcvs} co -d dir 1d1mod 2d2mod" \ -"${PROG} checkout: Updating dir/dir1d1 -U dir/dir1d1/file1 -${PROG} checkout: Updating dir/dir2d2/sub2d2 -U dir/dir2d2/sub2d2/file2" - dotest cvsadm-1d23b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d23d "cat dir/CVS/Repository" "\." - # the usual for 1d1mod - dotest cvsadm-1d23f "cat dir/dir1d1/CVS/Repository" "mod1" - # the usual for 2d2mod - dotest cvsadm-1d23h "cat dir/dir2d2/CVS/Repository" "mod2" - dotest cvsadm-1d23j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - - ### 1d2mod - - dotest cvsadm-1d24 "${testcvs} co -d dir 1d2mod 1d2mod-2" \ -"${PROG} checkout: Updating dir/dir1d2 -U dir/dir1d2/file2 -${PROG} checkout: Updating dir/dir1d2-2 -U dir/dir1d2-2/file2-2" - dotest cvsadm-1d24b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d24d "cat dir/CVS/Repository" "mod2" - # the usual for 1d2mod - dotest cvsadm-1d24f "cat dir/dir1d2/CVS/Repository" "mod2/sub2" - # the usual for 1d2mod copy - dotest cvsadm-1d24h "cat dir/dir1d2-2/CVS/Repository" "mod2-2/sub2-2" - rm -rf CVS dir - - dotest cvsadm-1d25 "${testcvs} co -d dir 1d2mod 2d1mod" \ -"${PROG} checkout: Updating dir/dir1d2 -U dir/dir1d2/file2 -${PROG} checkout: Updating dir/dir2d1/sub2d1 -U dir/dir2d1/sub2d1/file1" - dotest cvsadm-1d25b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d25d "cat dir/CVS/Repository" "mod2" - # the usual for 1d2mod - dotest cvsadm-1d25f "cat dir/dir1d2/CVS/Repository" "mod2/sub2" - # the usual for 2d1mod - dotest cvsadm-1d25h "cat dir/dir2d1/CVS/Repository" "\." - dotest cvsadm-1d25j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-1d26 "${testcvs} co -d dir 1d2mod 2d2mod" \ -"${PROG} checkout: Updating dir/dir1d2 -U dir/dir1d2/file2 -${PROG} checkout: Updating dir/dir2d2/sub2d2 -U dir/dir2d2/sub2d2/file2" - dotest cvsadm-1d26b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d26d "cat dir/CVS/Repository" "mod2" - # the usual for 1d2mod - dotest cvsadm-1d26f "cat dir/dir1d2/CVS/Repository" "mod2/sub2" - # the usual for 2d2mod - dotest cvsadm-1d26h "cat dir/dir2d2/CVS/Repository" "mod2" - dotest cvsadm-1d26j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - - # 2d1mod - - dotest cvsadm-1d27 "${testcvs} co -d dir 2d1mod 2d1mod-2" \ -"${PROG} checkout: Updating dir/dir2d1/sub2d1 -U dir/dir2d1/sub2d1/file1 -${PROG} checkout: Updating dir/dir2d1-2/sub2d1-2 -U dir/dir2d1-2/sub2d1-2/file1-2" - dotest cvsadm-1d27b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d27d "cat dir/CVS/Repository" "CVSROOT/Emptydir" - # the usual for 2d1mod - dotest cvsadm-1d27f "cat dir/dir2d1/CVS/Repository" "\." - dotest cvsadm-1d27h "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1" - # the usual for 2d1mod - dotest cvsadm-1d27j "cat dir/dir2d1-2/CVS/Repository" "\." - dotest cvsadm-1d27l "cat dir/dir2d1-2/sub2d1-2/CVS/Repository" \ -"mod1-2" - rm -rf CVS dir - - dotest cvsadm-1d28 "${testcvs} co -d dir 2d1mod 2d2mod" \ -"${PROG} checkout: Updating dir/dir2d1/sub2d1 -U dir/dir2d1/sub2d1/file1 -${PROG} checkout: Updating dir/dir2d2/sub2d2 -U dir/dir2d2/sub2d2/file2" - dotest cvsadm-1d28b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d28d "cat dir/CVS/Repository" "CVSROOT/Emptydir" - # the usual for 2d1mod - dotest cvsadm-1d28f "cat dir/dir2d1/CVS/Repository" "\." - dotest cvsadm-1d28h "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1" - # the usual for 2d2mod - dotest cvsadm-1d28j "cat dir/dir2d2/CVS/Repository" "mod2" - dotest cvsadm-1d28l "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - - # 2d2mod - - dotest cvsadm-1d29 "${testcvs} co -d dir 2d2mod 2d2mod-2" \ -"${PROG} checkout: Updating dir/dir2d2/sub2d2 -U dir/dir2d2/sub2d2/file2 -${PROG} checkout: Updating dir/dir2d2-2/sub2d2-2 -U dir/dir2d2-2/sub2d2-2/file2-2" - dotest cvsadm-1d29b "cat CVS/Repository" "\." - # the usual for the dir level - dotest cvsadm-1d29d "cat dir/CVS/Repository" "\." - # the usual for 2d2mod - dotest cvsadm-1d29f "cat dir/dir2d2/CVS/Repository" "mod2" - dotest cvsadm-1d29h "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - # the usual for 2d2mod - dotest cvsadm-1d29j "cat dir/dir2d2-2/CVS/Repository" "mod2-2" - dotest cvsadm-1d29l "cat dir/dir2d2-2/sub2d2-2/CVS/Repository" \ -"mod2-2/sub2-2" - rm -rf CVS dir - - ################################################## - ## And now, some of that again using the "-d" flag - ## on the command line, but use a longer path. - ################################################## - - dotest_fail cvsadm-2d3-1 "${testcvs} co -d dir/dir2 1mod" \ -"${PROG} \[checkout aborted\]: could not change directory to requested checkout directory .dir.: No such file or directory" - - if $remote; then :; else - # Remote can't handle this, even with the "mkdir dir". - # This was also true of CVS 1.9. - - mkdir dir - dotest cvsadm-2d3 "${testcvs} co -d dir/dir2 1mod" \ -"${PROG} checkout: Updating dir/dir2 -U dir/dir2/file1" - dotest cvsadm-2d3b "cat CVS/Repository" "\." - dotest_fail cvsadm-2d3d "test -f dir/CVS/Repository" "" - dotest cvsadm-2d3f "cat dir/dir2/CVS/Repository" "mod1" - rm -rf CVS dir - - mkdir dir - dotest cvsadm-2d4 "${testcvs} co -d dir/dir2 2mod" \ -"${PROG} checkout: Updating dir/dir2 -U dir/dir2/file2" - dotest cvsadm-2d4b "cat CVS/Repository" "\." - dotest cvsadm-2d4f "cat dir/dir2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - mkdir dir - dotest cvsadm-2d5 "${testcvs} co -d dir/dir2 1d1mod" \ -"${PROG} checkout: Updating dir/dir2 -U dir/dir2/file1" - dotest cvsadm-2d5b "cat CVS/Repository" "\." - dotest cvsadm-2d5f "cat dir/dir2/CVS/Repository" "mod1" - rm -rf CVS dir - - mkdir dir - dotest cvsadm-2d6 "${testcvs} co -d dir/dir2 1d2mod" \ -"${PROG} checkout: Updating dir/dir2 -U dir/dir2/file2" - dotest cvsadm-2d6b "cat CVS/Repository" "\." - dotest cvsadm-2d6f "cat dir/dir2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - mkdir dir - dotest cvsadm-2d7 "${testcvs} co -d dir/dir2 2d1mod" \ -"${PROG} checkout: Updating dir/dir2 -U dir/dir2/file1" - dotest cvsadm-2d7b "cat CVS/Repository" "\." - dotest cvsadm-2d7f "cat dir/dir2/CVS/Repository" "mod1" - rm -rf CVS dir - - mkdir dir - dotest cvsadm-2d8 "${testcvs} co -d dir/dir2 2d2mod" \ -"${PROG} checkout: Updating dir/dir2 -U dir/dir2/file2" - dotest cvsadm-2d8b "cat CVS/Repository" "\." - dotest cvsadm-2d8f "cat dir/dir2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - ################################################## - ## And now, a few of those tests revisited to - ## test the behavior of the -N flag. - ################################################## - - dotest cvsadm-N3 "${testcvs} co -N 1mod" \ -"${PROG} checkout: Updating 1mod -U 1mod/file1" - dotest cvsadm-N3b "cat CVS/Repository" "\." - dotest cvsadm-N3d "cat 1mod/CVS/Repository" "mod1" - rm -rf CVS 1mod - - dotest cvsadm-N4 "${testcvs} co -N 2mod" \ -"${PROG} checkout: Updating 2mod -U 2mod/file2" - dotest cvsadm-N4b "cat CVS/Repository" "\." - dotest cvsadm-N4d "cat 2mod/CVS/Repository" "mod2/sub2" - rm -rf CVS 2mod - - dotest cvsadm-N5 "${testcvs} co -N 1d1mod" \ -"${PROG} checkout: Updating dir1d1 -U dir1d1/file1" - dotest cvsadm-N5b "cat CVS/Repository" "\." - dotest cvsadm-N5d "cat dir1d1/CVS/Repository" "mod1" - rm -rf CVS dir1d1 - - dotest cvsadm-N6 "${testcvs} co -N 1d2mod" \ -"${PROG} checkout: Updating dir1d2 -U dir1d2/file2" - dotest cvsadm-N6b "cat CVS/Repository" "\." - dotest cvsadm-N6d "cat dir1d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir1d2 - - dotest cvsadm-N7 "${testcvs} co -N 2d1mod" \ -"${PROG} checkout: Updating dir2d1/sub2d1 -U dir2d1/sub2d1/file1" - dotest cvsadm-N7b "cat CVS/Repository" "\." - dotest cvsadm-N7d "cat dir2d1/CVS/Repository" "\." - dotest cvsadm-N7f "cat dir2d1/sub2d1/CVS/Repository" "mod1" - rm -rf CVS dir2d1 - - dotest cvsadm-N8 "${testcvs} co -N 2d2mod" \ -"${PROG} checkout: Updating dir2d2/sub2d2 -U dir2d2/sub2d2/file2" - dotest cvsadm-N8b "cat CVS/Repository" "\." - dotest cvsadm-N8d "cat dir2d2/CVS/Repository" "mod2" - dotest cvsadm-N8f "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir2d2 - - ## the ones in one-deep directories - - dotest cvsadm-N1d3 "${testcvs} co -N -d dir 1mod" \ -"${PROG} checkout: Updating dir/1mod -U dir/1mod/file1" - dotest cvsadm-N1d3b "cat CVS/Repository" "\." - dotest cvsadm-N1d3d "cat dir/CVS/Repository" "\." - dotest cvsadm-N1d3f "cat dir/1mod/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-N1d4 "${testcvs} co -N -d dir 2mod" \ -"${PROG} checkout: Updating dir/2mod -U dir/2mod/file2" - dotest cvsadm-N1d4b "cat CVS/Repository" "\." - dotest cvsadm-N1d4d "cat dir/CVS/Repository" "mod2" - dotest cvsadm-N1d4f "cat dir/2mod/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - dotest cvsadm-N1d5 "${testcvs} co -N -d dir 1d1mod" \ -"${PROG} checkout: Updating dir/dir1d1 -U dir/dir1d1/file1" - dotest cvsadm-N1d5b "cat CVS/Repository" "\." - dotest cvsadm-N1d5d "cat dir/CVS/Repository" "\." - dotest cvsadm-N1d5d "cat dir/dir1d1/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-N1d6 "${testcvs} co -N -d dir 1d2mod" \ -"${PROG} checkout: Updating dir/dir1d2 -U dir/dir1d2/file2" - dotest cvsadm-N1d6b "cat CVS/Repository" "\." - dotest cvsadm-N1d6d "cat dir/CVS/Repository" "mod2" - dotest cvsadm-N1d6f "cat dir/dir1d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - dotest cvsadm-N1d7 "${testcvs} co -N -d dir 2d1mod" \ -"${PROG} checkout: Updating dir/dir2d1/sub2d1 -U dir/dir2d1/sub2d1/file1" - dotest cvsadm-N1d7b "cat CVS/Repository" "\." - dotest cvsadm-N1d7d "cat dir/CVS/Repository" "CVSROOT/Emptydir" - dotest cvsadm-N1d7f "cat dir/dir2d1/CVS/Repository" "\." - dotest cvsadm-N1d7h "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1" - rm -rf CVS dir - - dotest cvsadm-N1d8 "${testcvs} co -N -d dir 2d2mod" \ -"${PROG} checkout: Updating dir/dir2d2/sub2d2 -U dir/dir2d2/sub2d2/file2" - dotest cvsadm-N1d8b "cat CVS/Repository" "\." - dotest cvsadm-N1d8d "cat dir/CVS/Repository" "\." - dotest cvsadm-N1d8d "cat dir/dir2d2/CVS/Repository" "mod2" - dotest cvsadm-N1d8d "cat dir/dir2d2/sub2d2/CVS/Repository" \ -"mod2/sub2" - rm -rf CVS dir - - ## the ones in two-deep directories - - mkdir dir - dotest cvsadm-N2d3 "${testcvs} co -N -d dir/dir2 1mod" \ -"${PROG} checkout: Updating dir/dir2/1mod -U dir/dir2/1mod/file1" - dotest cvsadm-N2d3b "cat CVS/Repository" "\." - dotest cvsadm-N2d3f "cat dir/dir2/CVS/Repository" "\." - dotest cvsadm-N2d3h "cat dir/dir2/1mod/CVS/Repository" "mod1" - rm -rf CVS dir - - mkdir dir - dotest cvsadm-N2d4 "${testcvs} co -N -d dir/dir2 2mod" \ -"${PROG} checkout: Updating dir/dir2/2mod -U dir/dir2/2mod/file2" - dotest cvsadm-N2d4b "cat CVS/Repository" "\." - dotest cvsadm-N2d4f "cat dir/dir2/CVS/Repository" "mod2" - dotest cvsadm-N2d4h "cat dir/dir2/2mod/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - mkdir dir - dotest cvsadm-N2d5 "${testcvs} co -N -d dir/dir2 1d1mod" \ -"${PROG} checkout: Updating dir/dir2/dir1d1 -U dir/dir2/dir1d1/file1" - dotest cvsadm-N2d5b "cat CVS/Repository" "\." - dotest cvsadm-N2d5f "cat dir/dir2/CVS/Repository" "\." - dotest cvsadm-N2d5h "cat dir/dir2/dir1d1/CVS/Repository" "mod1" - rm -rf CVS dir - - mkdir dir - dotest cvsadm-N2d6 "${testcvs} co -N -d dir/dir2 1d2mod" \ -"${PROG} checkout: Updating dir/dir2/dir1d2 -U dir/dir2/dir1d2/file2" - dotest cvsadm-N2d6b "cat CVS/Repository" "\." - dotest cvsadm-N2d6f "cat dir/dir2/CVS/Repository" "mod2" - dotest cvsadm-N2d6h "cat dir/dir2/dir1d2/CVS/Repository" "mod2/sub2" - rm -rf CVS dir - - mkdir dir - dotest cvsadm-N2d7 "${testcvs} co -N -d dir/dir2 2d1mod" \ -"${PROG} checkout: Updating dir/dir2/dir2d1/sub2d1 -U dir/dir2/dir2d1/sub2d1/file1" - dotest cvsadm-N2d7b "cat CVS/Repository" "\." - dotest cvsadm-N2d7f "cat dir/dir2/CVS/Repository" "CVSROOT/Emptydir" - dotest cvsadm-N2d7g "cat dir/dir2/dir2d1/CVS/Repository" "\." - dotest cvsadm-N2d7h "cat dir/dir2/dir2d1/sub2d1/CVS/Repository" \ -"mod1" - rm -rf CVS dir - - mkdir dir - dotest cvsadm-N2d8 "${testcvs} co -N -d dir/dir2 2d2mod" \ -"${PROG} checkout: Updating dir/dir2/dir2d2/sub2d2 -U dir/dir2/dir2d2/sub2d2/file2" - dotest cvsadm-N2d8b "cat CVS/Repository" "\." - dotest cvsadm-N2d8f "cat dir/dir2/CVS/Repository" "\." - dotest cvsadm-N2d8h "cat dir/dir2/dir2d2/CVS/Repository" "mod2" - dotest cvsadm-N2d8j "cat dir/dir2/dir2d2/sub2d2/CVS/Repository" \ -"mod2/sub2" - rm -rf CVS dir - - fi # end of tests to be skipped for remote - - ################################################## - ## That's enough of that, thank you very much. - ################################################## - - dotest cvsadm-cleanup-1 "${testcvs} -q co CVSROOT/config" \ -"U CVSROOT/config" - cd CVSROOT - echo "# empty file" >config - dotest cvsadm-cleanup-2 "${testcvs} -q ci -m cvsadm-cleanup" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd .. - rm -rf CVSROOT CVS - - # remove our junk - cd .. - rm -rf 1 - rm -rf ${CVSROOT_DIRNAME}/1mod - rm -rf ${CVSROOT_DIRNAME}/1mod-2 - rm -rf ${CVSROOT_DIRNAME}/2mod - rm -rf ${CVSROOT_DIRNAME}/2mod-2 - rm -rf ${CVSROOT_DIRNAME}/mod1 - rm -rf ${CVSROOT_DIRNAME}/mod1-2 - rm -rf ${CVSROOT_DIRNAME}/mod2 - rm -rf ${CVSROOT_DIRNAME}/mod2-2 - ;; - - emptydir) - # Various tests of the Emptydir (CVSNULLREPOS) code. See also: - # cvsadm: tests of Emptydir in various module definitions - # basicb: Test that "Emptydir" is non-special in ordinary contexts - - mkdir 1; cd 1 - dotest emptydir-1 "${testcvs} co CVSROOT/modules" \ -"U CVSROOT/modules" - echo "# Module defs for emptydir tests" > CVSROOT/modules - echo "2d1mod -d dir2d1/sub/sub2d1 mod1" >> CVSROOT/modules - echo "2d1moda -d dir2d1/suba moda/modasub" >> CVSROOT/modules - echo "2d1modb -d dir2d1/suba mod1" >> CVSROOT/modules - echo "comb -a 2d1modb 2d1moda" >> CVSROOT/modules - - dotest emptydir-2 "${testcvs} ci -m add-modules" \ -"${PROG} [a-z]*: Examining CVSROOT -Checking in CVSROOT/modules; -${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" \ -"${PROG} commit: Examining CVSROOT" - rm -rf CVS CVSROOT - - mkdir ${CVSROOT_DIRNAME}/mod1 ${CVSROOT_DIRNAME}/moda - # Populate. Not sure we really need to do this. - dotest emptydir-3 "${testcvs} -q co -l ." "" - dotest emptydir-3a "${testcvs} co mod1 moda" \ -"${PROG} checkout: Updating mod1 -${PROG} checkout: Updating moda" - echo "file1" > mod1/file1 - mkdir moda/modasub - dotest emptydir-3b "${testcvs} add moda/modasub" \ -"Directory ${CVSROOT_DIRNAME}/moda/modasub added to the repository" - echo "filea" > moda/modasub/filea - dotest emptydir-4 "${testcvs} add mod1/file1 moda/modasub/filea" \ -"${PROG} add: scheduling file .mod1/file1. for addition -${PROG} add: scheduling file .moda/modasub/filea. for addition -${PROG} add: 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 moda CVS - # End Populate. - - dotest emptydir-6 "${testcvs} co 2d1mod" \ -"${PROG} checkout: Updating dir2d1/sub/sub2d1 -U dir2d1/sub/sub2d1/file1" - cd dir2d1 - touch emptyfile - # It doesn't make any sense to add a file (or do much of anything - # else) in Emptydir; Emptydir is a placeholder indicating that - # the working directory doesn't correspond to anything in - # the repository. - dotest_fail emptydir-7 "${testcvs} add emptyfile" \ -"${PROG} \[add aborted\]: cannot add to ${CVSROOT_DIRNAME}/CVSROOT/Emptydir" - mkdir emptydir - dotest_fail emptydir-8 "${testcvs} add emptydir" \ -"${PROG} \[[a-z]* aborted\]: cannot add to ${CVSROOT_DIRNAME}/CVSROOT/Emptydir" - cd .. - rm -rf CVS dir2d1 - - # OK, while we have an Emptydir around, test a few obscure - # things about it. - mkdir edir; cd edir - dotest emptydir-9 "${testcvs} -q co -l CVSROOT" \ -"U CVSROOT${DOTSTAR}" - cd CVSROOT - dotest_fail emptydir-10 "test -d Emptydir" '' - # This tests the code in find_dirs which skips Emptydir. - 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. This used to show "Emptydir", - # but everyone seemed to think it should show "moda". This - # usually works better, but not always as shown by the following - # test. - dotest emptydir-13 "cat dir2d1/CVS/Repository" "moda" - dotest_fail emptydir-14 "${testcvs} co comb" \ -"${PROG} checkout: existing repository ${CVSROOT_DIRNAME}/moda/modasub does not match ${CVSROOT_DIRNAME}/mod1 -${PROG} checkout: ignoring module 2d1modb -${PROG} checkout: Updating dir2d1/suba" - dotest emptydir-15 "cat dir2d1/CVS/Repository" "moda" - cd .. - - # Test the effect of a non-cvs directory already existing with the - # same name as one in the modules file. - mkdir 3; cd 3 - mkdir dir2d1 - dotest emptydir-16 "${testcvs} co 2d1mod" \ -"${PROG} checkout: Updating dir2d1/sub/sub2d1 -U dir2d1/sub/sub2d1/file1" - dotest emptydir-17 "test -d dir2d1/CVS" - - # clean up - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd .. - rm -r 1 2 3 - 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 - ;; - - abspath) - - # These tests test the thituations thin thwitch thoo theck - # things thout twith thabsolute thaths. Threally. - - # - # CHECKOUTS - # - - # Create a few modules to use - mkdir ${CVSROOT_DIRNAME}/mod1 ${CVSROOT_DIRNAME}/mod2 - dotest abspath-1a "${testcvs} co mod1 mod2" \ -"${PROG} checkout: Updating mod1 -${PROG} checkout: Updating mod2" - - # Populate the module - echo "file1" > mod1/file1 - echo "file2" > mod2/file2 - cd mod1 - dotest abspath-1ba "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - cd .. - cd mod2 - dotest abspath-1bb "${testcvs} add file2" \ -"${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - cd .. - - dotest abspath-1c "${testcvs} ci -m yup mod1 mod2" \ -"${PROG} [a-z]*: Examining mod1 -${PROG} [a-z]*: Examining mod2 -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}/mod2/file2,v -done -Checking in mod2/file2; -${CVSROOT_DIRNAME}/mod2/file2,v <-- file2 -initial revision: 1.1 -done" - # Finished creating the module -- clean up. - rm -rf CVS mod1 mod2 - # Done. - - # Try checking out the module in a local directory - if $remote; then - dotest_fail abspath-2a "${testcvs} co -d ${TESTDIR}/1 mod1" \ -"${PROG} \[checkout aborted\]: absolute pathname .${TESTDIR}/1. illegal for server" - dotest abspath-2a-try2 "${testcvs} co -d 1 mod1" \ -"${PROG} checkout: Updating 1 -U 1/file1" - else - dotest abspath-2a "${testcvs} co -d ${TESTDIR}/1 mod1" \ -"${PROG} checkout: Updating ${TESTDIR}/1 -U ${TESTDIR}/1/file1" - fi # remote workaround - - dotest abspath-2b "cat ${TESTDIR}/1/CVS/Repository" "mod1" - - # Done. Clean up. - rm -rf ${TESTDIR}/1 - - - # Now try in a subdirectory. We're not covering any more - # code here, but we might catch a future error if someone - # changes the checkout code. - - # Note that for the same reason that the shell command - # "touch 1/2/3" requires directories 1 and 1/2 to already - # exist, we expect ${TESTDIR}/1 to already exist. I believe - # this is the behavior of CVS 1.9 and earlier. - if $remote; then :; else - dotest_fail abspath-3.1 "${testcvs} co -d ${TESTDIR}/1/2 mod1" \ -"${PROG} \[checkout aborted\]: could not change directory to requested checkout directory .${TESTDIR}/1.: No such file or directory" - fi - dotest_fail abspath-3.2 "${testcvs} co -d 1/2 mod1" \ -"${PROG} \[checkout aborted\]: could not change directory to requested checkout directory .1.: No such file or directory" - - mkdir 1 - - if $remote; then - # The server wants the directory to exist, but that is - # a bug, it should only need to exist on the client side. - # See also cvsadm-2d3. - dotest_fail abspath-3a "${testcvs} co -d 1/2 mod1" \ -"${PROG} \[checkout aborted\]: could not change directory to requested checkout directory .1.: No such file or directory" - cd 1 - dotest abspath-3a-try2 "${testcvs} co -d 2 mod1" \ -"${PROG} checkout: Updating 2 -U 2/file1" - cd .. - rm -rf 1/CVS - else - dotest abspath-3a "${testcvs} co -d ${TESTDIR}/1/2 mod1" \ -"${PROG} checkout: Updating ${TESTDIR}/1/2 -U ${TESTDIR}/1/2/file1" - fi # remote workaround - dotest abspath-3b "cat ${TESTDIR}/1/2/CVS/Repository" "mod1" - - # For all the same reasons that we want "1" to already - # exist, we don't to mess with it to traverse it, for - # example by creating a CVS directory. - - dotest_fail abspath-3c "test -d ${TESTDIR}/1/CVS" '' - # Done. Clean up. - rm -rf ${TESTDIR}/1 - - - # Now try someplace where we don't have permission. - mkdir ${TESTDIR}/barf - chmod -w ${TESTDIR}/barf - dotest_fail abspath-4r "${testcvs} co -d ${TESTDIR}/barf/sub mod1" \ -"${PROG} \[checkout aborted\]: absolute pathname .${TESTDIR}/barf/sub. illegal for server" \ -"${PROG} \[checkout aborted\]: cannot make directory sub: Permission denied" - chmod +w ${TESTDIR}/barf - rmdir ${TESTDIR}/barf - # Done. Nothing to clean up. - - - # Try checking out two modules into the same directory. - if $remote; then - dotest abspath-5ar "${testcvs} co -d 1 mod1 mod2" \ -"${PROG} checkout: Updating 1/mod1 -U 1/mod1/file1 -${PROG} checkout: Updating 1/mod2 -U 1/mod2/file2" - else - dotest abspath-5a "${testcvs} co -d ${TESTDIR}/1 mod1 mod2" \ -"${PROG} checkout: Updating ${TESTDIR}/1/mod1 -U ${TESTDIR}/1/mod1/file1 -${PROG} checkout: Updating ${TESTDIR}/1/mod2 -U ${TESTDIR}/1/mod2/file2" - fi # end remote workaround - dotest abspath-5b "cat ${TESTDIR}/1/CVS/Repository" "\." - dotest abspath-5c "cat ${TESTDIR}/1/mod1/CVS/Repository" "mod1" - dotest abspath-5d "cat ${TESTDIR}/1/mod2/CVS/Repository" "mod2" - # Done. Clean up. - rm -rf ${TESTDIR}/1 - - - # Try checking out the top-level module. - if $remote; then - dotest abspath-6ar "${testcvs} co -d 1 ." \ -"${PROG} checkout: Updating 1 -${PROG} checkout: Updating 1/CVSROOT -${DOTSTAR} -${PROG} checkout: Updating 1/mod1 -U 1/mod1/file1 -${PROG} checkout: Updating 1/mod2 -U 1/mod2/file2" - else - dotest abspath-6a "${testcvs} co -d ${TESTDIR}/1 ." \ -"${PROG} checkout: Updating ${TESTDIR}/1 -${PROG} checkout: Updating ${TESTDIR}/1/CVSROOT -${DOTSTAR} -${PROG} checkout: Updating ${TESTDIR}/1/mod1 -U ${TESTDIR}/1/mod1/file1 -${PROG} checkout: Updating ${TESTDIR}/1/mod2 -U ${TESTDIR}/1/mod2/file2" - fi # end of remote workaround - dotest abspath-6b "cat ${TESTDIR}/1/CVS/Repository" "\." - dotest abspath-6c "cat ${TESTDIR}/1/CVSROOT/CVS/Repository" "CVSROOT" - dotest abspath-6c "cat ${TESTDIR}/1/mod1/CVS/Repository" "mod1" - dotest abspath-6d "cat ${TESTDIR}/1/mod2/CVS/Repository" "mod2" - # Done. Clean up. - rm -rf ${TESTDIR}/1 - - # Test that an absolute pathname to some other directory - # doesn't mess with the current working directory. - mkdir 1 - cd 1 - if $remote; then - dotest_fail abspath-7ar "${testcvs} -q co -d ../2 mod2" \ -"${PROG} checkout: protocol error: .\.\./2. contains more leading \.\. -${PROG} \[checkout aborted\]: than the 0 which Max-dotdot specified" - cd .. - dotest abspath-7a-try2r "${testcvs} -q co -d 2 mod2" \ -"U 2/file2" - cd 1 - else - dotest abspath-7a "${testcvs} -q co -d ${TESTDIR}/2 mod2" \ -"U ${TESTDIR}/2/file2" - fi # remote workaround - dotest abspath-7b "ls" "" - dotest abspath-7c "${testcvs} -q co mod1" \ -"U mod1/file1" - cd mod1 - if $remote; then - cd ../.. - dotest abspath-7dr "${testcvs} -q co -d 3 mod2" \ -"U 3/file2" - cd 1/mod1 - else - dotest abspath-7d "${testcvs} -q co -d ${TESTDIR}/3 mod2" \ -"U ${TESTDIR}/3/file2" - fi # remote workaround - dotest abspath-7e "${testcvs} -q update -d" "" - cd ../.. - rm -r 1 2 3 - - # - # FIXME: do other functions here (e.g. update /tmp/foo) - # - - # Finished with all tests. Remove the module. - rm -rf ${CVSROOT_DIRNAME}/mod1 ${CVSROOT_DIRNAME}/mod2 - - ;; - - - - abspath2) - # More absolute path checks. The following used to attempt to create - # directories in /: - # - # $ cvs -d:fork:/cvsroot co /foo - # cvs checkout: warning: cannot make directory CVS in /: Permission denied - # cvs [checkout aborted]: cannot make directory /foo: Permission denied - # $ - # - # The -z9 in this test also checks for an old server bug where the - # server would block indefinitely attempting to read an EOF from the - # client in the compression buffer shutdown routine. - dotest_fail abspath2-1 "$testcvs -z9 co /foo" \ -"$PROG \[checkout aborted\]: Absolute module reference invalid: \`/foo'" \ -"$PROG \[server aborted\]: Absolute module reference invalid: \`/foo' -$PROG \[checkout aborted\]: end of file from server (consult above messages if any)" - ;; - - - - toplevel) - # test the feature that cvs creates a CVS subdir also for - # the toplevel directory - - # First set the TopLevelAdmin setting. - mkdir 1; cd 1 - dotest toplevel-1a "${testcvs} -q co CVSROOT/config" \ -"U CVSROOT/config" - cd CVSROOT - echo "TopLevelAdmin=yes" >config - dotest toplevel-1b "${testcvs} -q ci -m yes-top-level" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../.. - rm -r 1 - - mkdir 1; cd 1 - dotest toplevel-1 "${testcvs} -q co -l ." '' - mkdir top-dir second-dir - dotest toplevel-2 "${testcvs} add top-dir second-dir" \ -"Directory ${CVSROOT_DIRNAME}/top-dir added to the repository -Directory ${CVSROOT_DIRNAME}/second-dir added to the repository" - cd top-dir - - touch file1 - dotest toplevel-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest toplevel-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/top-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/top-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - cd .. - - cd second-dir - touch file2 - dotest toplevel-3s "${testcvs} add file2" \ -"${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest toplevel-4s "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/second-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/second-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - - cd ../.. - rm -r 1; mkdir 1; cd 1 - dotest toplevel-5 "${testcvs} co top-dir" \ -"${PROG} checkout: Updating top-dir -U top-dir/file1" - - dotest toplevel-6 "${testcvs} update top-dir" \ -"${PROG} update: Updating top-dir" - dotest toplevel-7 "${testcvs} update" \ -"${PROG} update: Updating \. -${PROG} update: Updating top-dir" - - dotest toplevel-8 "${testcvs} update -d top-dir" \ -"${PROG} update: Updating top-dir" - # There is some sentiment that - # "${PROG} update: Updating \. - # ${PROG} update: Updating top-dir" - # is correct but it isn't clear why that would be correct instead - # of the remote CVS behavior (which also updates CVSROOT). - # - # The DOTSTAR matches of a bunch of lines like - # "U CVSROOT/checkoutlist". Trying to match them more precisely - # seemed to cause trouble. For example CVSROOT/cvsignore will - # be present or absent depending on whether we ran the "ignore" - # test or not. - dotest toplevel-9 "${testcvs} update -d" \ -"${PROG} update: Updating \. -${PROG} update: Updating CVSROOT -${DOTSTAR} -${PROG} update: Updating top-dir" - - cd .. - rm -r 1; mkdir 1; cd 1 - dotest toplevel-10 "${testcvs} co top-dir" \ -"${PROG} checkout: Updating top-dir -U top-dir/file1" - - # This tests more or less the same thing, in a particularly - # "real life" example. - dotest toplevel-11 "${testcvs} -q update -d second-dir" \ -"U second-dir/file2" - - # Now remove the CVS directory (people may do this manually, - # especially if they formed their habits with CVS - # 1.9 and older, which didn't create it. Or perhaps the working - # directory itself was created with 1.9 or older). - rm -r CVS - # Now set the permissions so we can't recreate it. - if test -n "$remotehost"; then - # Cygwin again. - $CVS_RSH $remotehost "chmod -w $TESTDIR/1" - else - chmod -w ../1 - fi - # Now see whether CVS has trouble because it can't create CVS. - # First string is for local, second is for remote. - dotest toplevel-12 "${testcvs} co top-dir" \ -"${PROG} checkout: warning: cannot make directory CVS in \.: Permission denied -${PROG} checkout: Updating top-dir" \ -"${PROG} checkout: warning: cannot make directory CVS in \.: Permission denied -${PROG} checkout: in directory \.: -${PROG} checkout: cannot open CVS/Entries for reading: No such file or directory -${PROG} checkout: Updating top-dir" - - chmod +w ../1 - - dotest toplevel-cleanup-1 "${testcvs} -q co CVSROOT/config" \ -"U CVSROOT/config" - cd CVSROOT - echo "# empty file" >config - dotest toplevel-cleanup-2 "${testcvs} -q ci -m toplevel-cleanup" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/top-dir ${CVSROOT_DIRNAME}/second-dir - ;; - - toplevel2) - # Similar to toplevel, but test the case where TopLevelAdmin=no. - - # First set the TopLevelAdmin setting. - mkdir 1; cd 1 - dotest toplevel2-1a "${testcvs} -q co CVSROOT/config" \ -"U CVSROOT/config" - cd CVSROOT - echo "TopLevelAdmin=no" >config - dotest toplevel2-1b "${testcvs} -q ci -m no-top-level" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../.. - rm -r 1 - - # Now set up some directories and subdirectories - mkdir 1; cd 1 - dotest toplevel2-1 "${testcvs} -q co -l ." '' - mkdir top-dir second-dir - dotest toplevel2-2 "${testcvs} add top-dir second-dir" \ -"Directory ${CVSROOT_DIRNAME}/top-dir added to the repository -Directory ${CVSROOT_DIRNAME}/second-dir added to the repository" - cd top-dir - - touch file1 - dotest toplevel2-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest toplevel2-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/top-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/top-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - cd .. - - cd second-dir - touch file2 - dotest toplevel2-3s "${testcvs} add file2" \ -"${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest toplevel2-4s "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/second-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/second-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - - cd ../.. - rm -r 1; mkdir 1; cd 1 - dotest toplevel2-5 "${testcvs} co top-dir" \ -"${PROG} checkout: Updating top-dir -U top-dir/file1" - - dotest toplevel2-6 "${testcvs} update top-dir" \ -"${PROG} update: Updating top-dir" - dotest toplevel2-7 "${testcvs} update" \ -"${PROG} update: Updating top-dir" - - dotest toplevel2-8 "${testcvs} update -d top-dir" \ -"${PROG} update: Updating top-dir" - # Contrast this with toplevel-9, which has TopLevelAdmin=yes. - dotest toplevel2-9 "${testcvs} update -d" \ -"${PROG} update: Updating top-dir" - - cd .. - rm -r 1; mkdir 1; cd 1 - dotest toplevel2-10 "${testcvs} co top-dir" \ -"${PROG} checkout: Updating top-dir -U top-dir/file1" - # This tests more or less the same thing, in a particularly - # "real life" example. With TopLevelAdmin=yes, this command - # would give us second-dir and CVSROOT directories too. - dotest toplevel2-11 "${testcvs} -q update -d" "" - - dotest toplevel2-cleanup-1 "${testcvs} -q co CVSROOT/config" \ -"U CVSROOT/config" - cd CVSROOT - echo "# empty file" >config - dotest toplevel2-cleanup-2 "${testcvs} -q ci -m toplevel2-cleanup" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/top-dir ${CVSROOT_DIRNAME}/second-dir - ;; - - - - rstar-toplevel) - # This test used to confirm a bug that existed in the r* commands - # run against the top-level project prior to CVS 1.11.18 & 1.12.10. - # - # The assertion failure was something like: - # do_recursion: Assertion \`strstr (repository, \"/\./\") == ((void \*)0)' failed\..*" - dotest rstar-toplevel-1 "$testcvs -q rlog ." \ -" -RCS file: $CVSROOT_DIRNAME/CVSROOT$DOTSTAR" - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - ;; - - - - trailingslashes) - # Some tests of CVS's reactions to path specifications containing - # trailing slashes. - mkdir trailingslashes; cd trailingslashes - dotest trailingslashes-init-1 "$testcvs -Q co -ldt ." - dotest trailingslashes-init-2 "$testcvs -Q co -dt2 ." - cd t - echo "Ahh'll be baaack." >topfile - dotest trailingslashes-init-3 "$testcvs -Q add topfile" - dotest trailingslashes-init-4 "$testcvs -Q ci -mto-top" \ -"RCS file: $CVSROOT_DIRNAME/topfile,v -done -Checking in topfile; -$CVSROOT_DIRNAME/topfile,v <-- topfile -initial revision: 1\.1 -done" - - # First, demonstrate the usual case. - cd ../t2 - dotest trailingslashes-1 "$testcvs -q up CVSROOT" - dotest_fail trailingslashes-1a "test -f topfile" - - # Now the one that used to fail in remote mode prior to 1.11.24 - # & 1.12.14. Formerly TODO item #205. - dotest trailingslashes-2 "$testcvs -q up CVSROOT/" - dotest_fail trailingslashes-2a "test -f topfile" - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd ../.. - rm -rf trailingslashes $CVSROOT_DIRNAME/topfile,v - ;; - - - - checkout_repository) - dotest_fail checkout_repository-1 \ -"${testcvs} co -d ${CVSROOT_DIRNAME} CVSROOT" \ -"${PROG} \[checkout aborted\]: Cannot check out files into the repository itself" \ -"${PROG} \[checkout aborted\]: absolute pathname \`${CVSROOT_DIRNAME}' illegal for server" - - # The behavior of the client/server test below should be correct. - # The CVS client currently has no way of knowing that the client and - # server are the same machine and thus skips the $CVSROOT checks. - # I think checking for this case in CVS would be bloat since this - # should be a fairly rare occurance. - cd ${CVSROOT_DIRNAME} - dotest_fail checkout_repository-2 "${testcvs} co CVSROOT" \ -"${PROG} \[checkout aborted\]: Cannot check out files into the repository itself" \ -"${PROG} checkout: Updating CVSROOT -${PROG} checkout: move away CVSROOT/checkoutlist; it is in the way -C CVSROOT/checkoutlist -${PROG} checkout: move away CVSROOT/commitinfo; it is in the way -C CVSROOT/commitinfo -${PROG} checkout: move away CVSROOT/config; it is in the way -C CVSROOT/config -${PROG} checkout: move away CVSROOT/cvswrappers; it is in the way -C CVSROOT/cvswrappers -${PROG} checkout: move away CVSROOT/editinfo; it is in the way -C CVSROOT/editinfo -${PROG} checkout: move away CVSROOT/loginfo; it is in the way -C CVSROOT/loginfo -${PROG} checkout: move away CVSROOT/modules; it is in the way -C CVSROOT/modules -${PROG} checkout: move away CVSROOT/notify; it is in the way -C CVSROOT/notify -${PROG} checkout: move away CVSROOT/rcsinfo; it is in the way -C CVSROOT/rcsinfo -${PROG} checkout: move away CVSROOT/taginfo; it is in the way -C CVSROOT/taginfo -${PROG} checkout: move away CVSROOT/verifymsg; it is in the way -C CVSROOT/verifymsg" - - dotest checkout_repository-3 \ -"${testcvs} co -p CVSROOT/modules >/dev/null" \ -"=================================================================== -Checking out CVSROOT/modules -RCS: ${CVSROOT_DIRNAME}/CVSROOT/modules,v -VERS: 1\.[0-9]* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*" - cd ${TESTDIR} - ;; - - mflag) - for message in '' ' ' ' - ' ' test' ; do - # Set up - mkdir a-dir; cd a-dir - # Test handling of -m during import - echo testa >>test - if ${testcvs} import -m "$message" a-dir A A1 >>${LOGFILE} 2>&1;then - pass 156 - else - fail 156 - fi - # Must import twice since the first time uses inline code that - # avoids RCS call. - echo testb >>test - if ${testcvs} import -m "$message" a-dir A A2 >>${LOGFILE} 2>&1;then - pass 157 - else - fail 157 - fi - # Test handling of -m during ci - cd ..; rm -r a-dir - if ${testcvs} co a-dir >>${LOGFILE} 2>&1; then - pass 158 - else - fail 158 - fi - cd a-dir - echo testc >>test - if ${testcvs} ci -m "$message" >>${LOGFILE} 2>&1; then - pass 159 - else - fail 159 - fi - # Test handling of -m during rm/ci - rm test; - if ${testcvs} rm test >>${LOGFILE} 2>&1; then - pass 160 - else - fail 160 - fi - if ${testcvs} ci -m "$message" >>${LOGFILE} 2>&1; then - pass 161 - else - fail 161 - fi - # Clean up - cd .. - rm -r a-dir - rm -rf ${CVSROOT_DIRNAME}/a-dir - done - ;; - - editor) - # More tests of log messages, in this case the ability to - # run an external editor. - # TODO: - # * also test $EDITOR, $CVSEDITOR, &c. - # * test what happens if up-to-date check fails. - - # Our "editor" puts "x" at the start of each line, so we - # can see the "CVS:" lines. - cat >${TESTDIR}/editme <<EOF -#!${TESTSHELL} -sleep 1 -sed <\$1 -e 's/^/x/' >${TESTDIR}/edit.new -mv ${TESTDIR}/edit.new \$1 -exit 0 -EOF - chmod +x ${TESTDIR}/editme - - mkdir 1; cd 1 - dotest editor-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest editor-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch file1 file2 - dotest editor-3 "${testcvs} add file1 file2" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest editor-4 "${testcvs} -e ${TESTDIR}/editme -q ci" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - dotest editor-5 "${testcvs} -q tag -b br" "T file1 -T file2" - dotest editor-6 "$testcvs -q update -r br" \ -'U file1 -U file2' - echo modify >>file1 - dotest editor-7 "${testcvs} -e ${TESTDIR}/editme -q ci" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - # OK, now we want to make sure "ci -r" puts in the branch - # where appropriate. Note that we can check in on the branch - # without being on the branch, because there is not a revision - # already on the branch. If there were a revision on the branch, - # CVS would correctly give an up-to-date check failed. - dotest editor-8 "$testcvs -q update -A" \ -'U file1 -U file2' - echo add a line >>file2 - dotest editor-9 "${testcvs} -q -e ${TESTDIR}/editme ci -rbr file2" \ -"Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - dotest editor-log-file1 "${testcvs} log -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -branches: 1\.1\.2; -xCVS: ---------------------------------------------------------------------- -xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically -xCVS: -xCVS: Committing in . -xCVS: -xCVS: Added Files: -xCVS: file1 file2 -xCVS: ---------------------------------------------------------------------- ----------------------------- -revision 1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -xCVS: ---------------------------------------------------------------------- -xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically -xCVS: -xCVS: Committing in . -xCVS: -xCVS: Modified Files: -xCVS: Tag: br -xCVS: file1 -xCVS: ---------------------------------------------------------------------- -=============================================================================" - - # The only difference between the two expect strings is the - # presence or absence of "Committing in ." for 1.1.2.1. - dotest editor-log-file2 "${testcvs} log -N file2" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -Working file: file2 -head: 1\.1 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -branches: 1\.1\.2; -xCVS: ---------------------------------------------------------------------- -xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically -xCVS: -xCVS: Committing in . -xCVS: -xCVS: Added Files: -xCVS: file1 file2 -xCVS: ---------------------------------------------------------------------- ----------------------------- -revision 1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -xCVS: ---------------------------------------------------------------------- -xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically -xCVS: -xCVS: Modified Files: -xCVS: Tag: br -xCVS: file2 -xCVS: ---------------------------------------------------------------------- -=============================================================================" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -Working file: file2 -head: 1\.1 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -branches: 1\.1\.2; -xCVS: ---------------------------------------------------------------------- -xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically -xCVS: -xCVS: Committing in . -xCVS: -xCVS: Added Files: -xCVS: file1 file2 -xCVS: ---------------------------------------------------------------------- ----------------------------- -revision 1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -xCVS: ---------------------------------------------------------------------- -xCVS: Enter Log. Lines beginning with .CVS:. are removed automatically -xCVS: -xCVS: Committing in . -xCVS: -xCVS: Modified Files: -xCVS: Tag: br -xCVS: file2 -xCVS: ---------------------------------------------------------------------- -=============================================================================" - - # Test CVS's response to an unchanged log message - cat >${TESTDIR}/editme <<EOF -#!${TESTSHELL} -sleep 1 -exit 0 -EOF - chmod +x ${TESTDIR}/editme - dotest_fail editor-emptylog-1 "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \ -" -Log message unchanged or not specified -a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs -Action: (continue) ${PROG} \[[a-z]* aborted\]: aborted by user" - - # Test CVS's response to an empty log message - cat >${TESTDIR}/editme <<EOF -#!${TESTSHELL} -sleep 1 -cat /dev/null >\$1 -exit 0 -EOF - chmod +x ${TESTDIR}/editme - dotest_fail editor-emptylog-1 "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \ -" -Log message unchanged or not specified -a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs -Action: (continue) ${PROG} \[[a-z]* aborted\]: aborted by user" - - # Test CVS's response to a log message with one blank line - cat >${TESTDIR}/editme <<EOF -#!${TESTSHELL} -sleep 1 -echo >\$1 -exit 0 -EOF - chmod +x ${TESTDIR}/editme - dotest_fail editor-emptylog-1 "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \ -" -Log message unchanged or not specified -a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs -Action: (continue) ${PROG} \[[a-z]* aborted\]: aborted by user" - - # Test CVS's response to a log message with only comments - cat >${TESTDIR}/editme <<EOF -#!${TESTSHELL} -sleep 1 -cat \$1 >${TESTDIR}/edit.new -mv ${TESTDIR}/edit.new \$1 -exit 0 -EOF - chmod +x ${TESTDIR}/editme - dotest_fail editor-emptylog-1 "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \ -" -Log message unchanged or not specified -a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs -Action: (continue) ${PROG} \[[a-z]* aborted\]: aborted by user" - - # Test CVS's response to a log message that is zero bytes - # in length. This caused core dumps in cvs 1.11.5 on Solaris - # hosts. - cd .. - dotest editor-emptylog-continue-1 "${testcvs} -q co CVSROOT/loginfo" \ -"U CVSROOT/loginfo" - - cd CVSROOT - echo 'DEFAULT (echo Start-Log;cat;echo End-Log) >> \$CVSROOT/CVSROOT/commitlog' > loginfo - dotest editor-emptylog-continue-2 "${testcvs} commit -m add loginfo" \ -"Checking in loginfo; -${CVSROOT_DIRNAME}/CVSROOT/loginfo,v <-- loginfo -new revision: 1\.2; previous revision: 1\.1 -done -${PROG} commit: Rebuilding administrative file database" - - cd ../first-dir - cat >${TESTDIR}/editme <<EOF -#!${TESTSHELL} -sleep 1 -cp /dev/null \$1 -exit 1 -EOF - chmod +x ${TESTDIR}/editme - dotest editor-emptylog-continue-3 "echo c |${testcvs} -e ${TESTDIR}/editme ci -f file1" \ -"${PROG} [a-z]*: warning: editor session failed - -Log message unchanged or not specified -a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs -Action: (continue) Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - # The loginfo Log message should be an empty line and not "(null)" - # which is what some fprintf() implementations do with "%s" - # format and a NULL pointer... - if $remote; then - dotest editor-emptylog-continue-4r \ -"cat ${CVSROOT_DIRNAME}/CVSROOT/commitlog" \ -"Start-Log -Update of ${CVSROOT_DIRNAME}/first-dir -In directory ${hostname}:${TMPDIR}/cvs-serv[0-9a-z]* - -Modified Files: - file1 -Log Message: - -End-Log" - else - dotest editor-emptylog-continue-4 \ -"cat ${CVSROOT_DIRNAME}/CVSROOT/commitlog" \ -"Start-Log -Update of ${CVSROOT_DIRNAME}/first-dir -In directory ${hostname}:${TESTDIR}/1/first-dir - -Modified Files: - file1 -Log Message: - -End-Log" - fi - # There should have an empty log message at this point - dotest editor-emptylog-continue-5 "${testcvs} log -N -r1.2 file1" \ -" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.2 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 3; selected revisions: 1 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: +0 -0 -\*\*\* empty log message \*\*\* -=============================================================================" - - # clean up - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - restore_adm - cd ../.. - rm -r 1 - rm ${TESTDIR}/editme - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - errmsg1) - mkdir ${CVSROOT_DIRNAME}/1dir - mkdir 1 - cd 1 - if ${testcvs} -q co 1dir; then - pass 162 - else - fail 162 - fi - cd 1dir - touch foo - if ${testcvs} add foo 2>>${LOGFILE}; then - pass 163 - else - fail 163 - fi - if ${testcvs} ci -m added >>${LOGFILE} 2>&1; then - pass 164 - else - fail 164 - fi - cd ../.. - mkdir 2 - cd 2 - if ${testcvs} -q co 1dir >>${LOGFILE}; then - pass 165 - else - fail 165 - fi - chmod a-w 1dir - cd ../1/1dir - rm foo; - if ${testcvs} rm foo >>${LOGFILE} 2>&1; then - pass 166 - else - fail 166 - fi - if ${testcvs} ci -m removed >>${LOGFILE} 2>&1; then - pass 167 - else - fail 167 - fi - - cd ../../2/1dir - # The second case in the local and remote versions of errmsg1-168 - # below happens on Cygwin under Windows, where write privileges - # aren't enforced properly. - if $remote; then - dotest errmsg1-168r "${testcvs} -q update" \ -"${PROG} update: foo is no longer in the repository -${PROG} update: unable to remove \./foo: Permission denied" \ -"${PROG} update: foo is no longer in the repository" - else - dotest errmsg1-168 "${testcvs} -q update" \ -"${PROG} update: foo is no longer in the repository -${PROG} update: unable to remove foo: Permission denied" \ -"${PROG} update: foo is no longer in the repository" - fi - - cd .. - chmod u+w 1dir - cd .. - rm -r 1 2 - rm -rf ${CVSROOT_DIRNAME}/1dir - ;; - - errmsg2) - # More tests of various miscellaneous error handling, - # and cvs add behavior in general. - # See also test basicb-4a, concerning "cvs ci CVS". - # Too many tests to mention test the simple cases of - # adding files and directories. - # Test basicb-2a10 tests cvs -n add. - - # First the usual setup; create a directory first-dir. - mkdir 1; cd 1 - dotest errmsg2-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest errmsg2-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - dotest_fail errmsg2-3 "${testcvs} add CVS" \ -"${PROG} [a-z]*: cannot add special file .CVS.; skipping" - touch file1 - # For the most part add returns a failure exitstatus if - # there are any errors, even if the remaining files are - # processed without incident. The "cannot add - # special file" message fits this pattern, at - # least currently. - dotest_fail errmsg2-4 "${testcvs} add CVS file1" \ -"${PROG} add: cannot add special file .CVS.; skipping -${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - # I'm not sure these tests completely convey the various strange - # behaviors that CVS had before it specially checked for "." and - # "..". Suffice it to say that these are unlikely to work right - # without a special case. - dotest_fail errmsg2-5 "${testcvs} add ." \ -"${PROG} [a-z]*: cannot add special file .\..; skipping" - dotest_fail errmsg2-6 "${testcvs} add .." \ -"${PROG} [a-z]*: cannot add special file .\.\..; skipping" - # Make sure that none of the error messages left droppings - # which interfere with normal operation. - dotest errmsg2-7 "${testcvs} -q ci -m add-file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - mkdir sdir - cd .. - dotest errmsg2-8 "${testcvs} add first-dir/sdir" \ -"Directory ${CVSROOT_DIRNAME}/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 - - touch file10 - mkdir sdir10 - dotest errmsg2-10 "${testcvs} add file10 sdir10" \ -"${PROG} add: scheduling file .file10. for addition -Directory ${CVSROOT_DIRNAME}/first-dir/sdir10 added to the repository -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest errmsg2-11 "${testcvs} -q ci -m add-file10" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file10,v -done -Checking in file10; -${CVSROOT_DIRNAME}/first-dir/file10,v <-- file10 -initial revision: 1\.1 -done" - # Try to see that there are no droppings left by - # any of the previous tests. - dotest errmsg2-12 "${testcvs} -q update" "" - - # Now test adding files with '/' in the name, both one level - # down and more than one level down. - cd .. - mkdir first-dir/sdir10/ssdir - dotest errmsg2-13 "${testcvs} add first-dir/sdir10/ssdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/sdir10/ssdir added to the repository" - - touch first-dir/sdir10/ssdir/ssfile - dotest errmsg2-14 \ - "${testcvs} add first-dir/sdir10/ssdir/ssfile" \ -"${PROG} add: scheduling file .first-dir/sdir10/ssdir/ssfile. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - touch first-dir/file15 - dotest errmsg2-15 "${testcvs} add first-dir/file15" \ -"${PROG} add: scheduling file .first-dir/file15. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - - # Now the case where we try to give it a directory which is not - # under CVS control. - mkdir bogus-dir - touch bogus-dir/file16 - # The first message, from local CVS, is nice. The second one - # is not nice; would be good to fix remote CVS to give a clearer - # message (e.g. the one from local CVS). But at least it is an - # error message. - dotest_fail errmsg2-16 "${testcvs} add bogus-dir/file16" \ -"${PROG} add: in directory bogus-dir: -${PROG} \[add aborted\]: there is no version here; do .${PROG} checkout. first" \ -"${PROG} add: cannot open CVS/Entries for reading: No such file or directory -${PROG} \[add aborted\]: no repository" - rm -r bogus-dir - - # One error condition we don't test for is trying to add a file - # or directory which already is there. - - dotest errmsg2-17 "${testcvs} -q ci -m checkin" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file15,v -done -Checking in first-dir/file15; -${CVSROOT_DIRNAME}/first-dir/file15,v <-- file15 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir10/ssdir/ssfile,v -done -Checking in first-dir/sdir10/ssdir/ssfile; -${CVSROOT_DIRNAME}/first-dir/sdir10/ssdir/ssfile,v <-- ssfile -initial revision: 1\.1 -done" - dotest errmsg2-18 "${testcvs} -Q tag test" '' - - # trying to import the repository - - if $remote; then :; else - cd ${CVSROOT_DIRNAME} - dotest_fail errmsg2-20 "${testcvs} import -mtest . A B" \ -"${PROG} \[import aborted\]: attempt to import the repository" - dotest_fail errmsg2-21 "${testcvs} import -mtest first-dir A B" \ -"${PROG} \[import aborted\]: attempt to import the repository" - fi - - cd .. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - adderrmsg) - # Test some of the error messages the 'add' command can return and - # their reactions to '-q'. - - # First the usual setup; create a directory first-dir. - mkdir 1; cd 1 - dotest adderrmsg-init1 "${testcvs} -q co -l ." '' - mkdir adderrmsg-dir - dotest adderrmsg-init2 "${testcvs} add adderrmsg-dir" \ -"Directory ${CVSROOT_DIRNAME}/adderrmsg-dir added to the repository" - cd adderrmsg-dir - - # try to add the admin dir - dotest_fail adderrmsg-1 "${testcvs} add CVS" \ -"${PROG} [a-z]*: cannot add special file .CVS.; skipping" - # might not want to see this message when you 'cvs add *' - dotest_fail adderrmsg-2 "${testcvs} -q add CVS" "" - - # to test some other messages - touch file1 - dotest adderrmsg-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - - # add it twice - dotest_fail adderrmsg-4 "${testcvs} add file1" \ -"${PROG} add: file1 has already been entered" - dotest_fail adderrmsg-5 "${testcvs} -q add file1" "" - - dotest adderrmsg-6 "${testcvs} -q ci -madd" \ -"RCS file: ${CVSROOT_DIRNAME}/adderrmsg-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/adderrmsg-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - - # file in Entries & repository - dotest_fail adderrmsg-7 "${testcvs} add file1" \ -"${PROG} add: file1 already exists, with version number 1\.1" - dotest_fail adderrmsg-8 "${testcvs} -q add file1" "" - - # clean up - cd ../.. - if $keep; then :; else - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/adderrmsg-dir - fi - ;; - - opterrmsg) - # Test some option parsing error messages - - # No init is necessary since these error messages are printed b4 - # CVS looks for a sandbox or repository - - # -z used to accept non-numeric arguments. This bit someone who - # attempted `cvs -z -n up' when the -n was read as the argument to - # -z. - dotest_fail opterrmsg-1 "${testcvs} -z -n up" \ -"${PROG}: gzip compression level must be between 0 and 9" - - # Some general -z checks - dotest_fail opterrmsg-2 "${testcvs} -z -1 up" \ -"${PROG}: gzip compression level must be between 0 and 9" - dotest_fail opterrmsg-3 "${testcvs} -z10 up" \ -"${PROG}: gzip compression level must be between 0 and 9" - ;; - - devcom) - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir 1 - cd 1 - dotest devcom-1 "${testcvs} -q co first-dir" - - cd first-dir - echo abb >abb - dotest devcom-2 "${testcvs} add abb" \ -"$PROG add: scheduling file \`abb' for addition -$PROG add: use '$PROG commit' to add this file permanently" - - dotest devcom-3 "${testcvs} -q ci -m added" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/abb,v -done -Checking in abb; -${CVSROOT_DIRNAME}/first-dir/abb,v <-- abb -initial revision: 1\.1 -done" - - dotest_fail devcom-4 "${testcvs} watch" "Usage${DOTSTAR}" - - dotest devcom-5 "${testcvs} watch on" - - echo abc >abc - dotest devcom-6 "${testcvs} add abc" \ -"$PROG add: scheduling file \`abc' for addition -$PROG add: use '$PROG commit' to add this file permanently" - - dotest devcom-7 "${testcvs} -q ci -m added" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v -done -Checking in abc; -${CVSROOT_DIRNAME}/first-dir/abc,v <-- abc -initial revision: 1\.1 -done" - - cd ../.. - mkdir 2 - cd 2 - - dotest devcom-8 "${testcvs} -q co first-dir" \ -"U first-dir/abb -U first-dir/abc" - - cd first-dir - dotest_fail devcom-9 "test -w abb" - dotest_fail devcom-9 "test -w abc" - - dotest devcom-10 "${testcvs} editors" "" - - dotest devcom-11 "${testcvs} edit abb" - - # Here we test for the traditional ISO C ctime() date format. - # We assume the C locale; I guess that works provided we set - # LC_ALL at the start of this script but whether these - # strings should vary based on locale does not strike me as - # self-evident. - dotest devcom-12 "${testcvs} editors" \ -"abb ${username} [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] GMT [-a-zA-Z_.0-9]* ${TESTDIR}/2/first-dir" - - echo aaaa >>abb - dotest devcom-13 "${testcvs} ci -m modify abb" \ -"Checking in abb; -${CVSROOT_DIRNAME}/first-dir/abb,v <-- abb -new revision: 1\.2; previous revision: 1\.1 -done" - - # Unedit of a file not being edited should be a noop. - dotest devcom-14 "${testcvs} unedit abb" '' - - dotest devcom-15 "${testcvs} editors" "" - - dotest_fail devcom-16 "test -w abb" - - dotest devcom-17 "${testcvs} edit abc" - - # Unedit of an unmodified file. - dotest devcom-18 "${testcvs} unedit abc" - dotest devcom-19 "${testcvs} edit abc" - - echo changedabc >abc - # Try to unedit a modified file; cvs should ask for confirmation - dotest devcom-20 "echo no | ${testcvs} unedit abc" \ -"abc has been modified; revert changes? " - - dotest devcom-21 "echo changedabc | cmp - abc" - - # OK, now confirm the unedit - dotest devcom-22 "echo yes | ${testcvs} unedit abc" \ -"abc has been modified; revert changes? " - - dotest devcom-23 "echo abc | cmp - abc" - - dotest devcom-24 "${testcvs} watchers" '' - - # FIXME: This probably should be an error message instead - # of silently succeeding and printing nothing. - dotest devcom-a-nonexist "${testcvs} watchers nonexist" '' - - dotest devcom-a1 "${testcvs} watch add" '' - dotest devcom-a2 "${testcvs} watchers" \ -"abb ${username} edit unedit commit -abc ${username} edit unedit commit" - dotest devcom-a3 "${testcvs} watch remove -a unedit abb" '' - dotest devcom-a4 "${testcvs} watchers abb" \ -"abb ${username} edit commit" - - # Check tagging and checking out while we have a CVS - # directory in the repository. - dotest devcom-t0 "${testcvs} -q tag tag" \ -'T abb -T abc' - cd ../.. - mkdir 3 - cd 3 - - # Test commented out because the bug it tests for is not fixed - # The error is: - # cvs watchers: cannot open CVS/Entries for reading: No such file or directory - # cvs: ../../work/ccvs/src/fileattr.c:75: fileattr_read: Assertion `fileattr_stored_repos != ((void *)0)' failed. -: dotest devcom-t-nonexist "${testcvs} watchers nonexist" fixme - - dotest devcom-t1 "${testcvs} -q co -rtag first-dir/abb" \ -'U first-dir/abb' - cd .. - # Since first-dir/abb is readonly, use -f. - rm -rf 3 - - # Test checking out the directory rather than the file. - mkdir 3 - cd 3 - dotest devcom-t2 "${testcvs} -q co -rtag first-dir" \ -'U first-dir/abb -U first-dir/abc' - cd .. - # Since the files are readonly, use -f. - rm -rf 3 - - # Now do it again, after removing the val-tags file created - # by devcom-t1 to force CVS to search the repository - # containing CVS directories. - rm -f ${CVSROOT_DIRNAME}/CVSROOT/val-tags - mkdir 3 - cd 3 - dotest devcom-t3 "${testcvs} -q co -rtag first-dir" \ -'U first-dir/abb -U first-dir/abc' - cd .. - # Since the files are readonly, use -f. - rm -rf 3 - - # Now remove all the file attributes - cd 2/first-dir - dotest devcom-b0 "${testcvs} watch off" '' - dotest devcom-b1 "${testcvs} watch remove" '' - # Test that CVS 1.6 and earlier can handle the repository. - dotest_fail devcom-b2 "test -d ${CVSROOT_DIRNAME}/first-dir/CVS" - - # Now test watching just some, not all, files. - dotest devcom-some0 "${testcvs} watch on abc" '' - cd ../.. - mkdir 3 - cd 3 - dotest devcom-some1 "${testcvs} -q co first-dir" 'U first-dir/abb -U first-dir/abc' - dotest devcom-some2 "test -w first-dir/abb" '' - dotest_fail devcom-some3 "test -w first-dir/abc" '' - cd .. - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - # Use -f because of the readonly files. - rm -rf 1 2 3 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - devcom2) - # More watch tests, most notably setting watches on - # files in various different states. - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir 1 - cd 1 - dotest devcom2-1 "${testcvs} -q co first-dir" '' - cd first-dir - - # This should probably be an error; setting a watch on a totally - # unknown file is more likely to be a typo than intentional. - # But that isn't the currently implemented behavior. - dotest devcom2-2 "${testcvs} watch on w1" '' - - touch w1 w2 w3 nw1 - dotest devcom2-3 "${testcvs} add w1 w2 w3 nw1" "${DOTSTAR}" - # Letting the user set the watch here probably can be considered - # a feature--although it leads to a few potentially strange - # consequences like one user can set the watch and another actually - # adds the file. - dotest devcom2-4 "${testcvs} watch on w2" '' - dotest devcom2-5 "${testcvs} -q ci -m add-them" "${DOTSTAR}" - - # Note that this test differs in a subtle way from devcom-some0; - # in devcom-some0 the watch is creating a new fileattr file, and - # here we are modifying an existing one. - dotest devcom2-6 "${testcvs} watch on w3" '' - - # Now test that all the watches got set on the correct files - # FIXME: CVS should have a way to report whether watches are - # set, I think. The "check it out and see if it read-only" is - # sort of OK, but is complicated by CVSREAD and doesn't help - # if the file is added and not yet committed or some such. - # Probably "cvs status" should report "watch: on" if watch is on - # (and nothing if watch is off, so existing behavior is preserved). - cd ../.. - mkdir 2 - cd 2 - dotest devcom2-7 "${testcvs} -q co first-dir" 'U first-dir/nw1 -U first-dir/w1 -U first-dir/w2 -U first-dir/w3' - dotest devcom2-8 "test -w first-dir/nw1" '' - dotest_fail devcom2-9 "test -w first-dir/w1" '' - dotest_fail devcom2-10 "test -w first-dir/w2" '' - dotest_fail devcom2-11 "test -w first-dir/w3" '' - - cd first-dir - # OK, now we want to try files in various states with cvs edit. - dotest devcom2-12 "${testcvs} edit w4" \ -"${PROG} edit: no such file w4; ignored" - # Try the same thing with a per-directory watch set. - dotest devcom2-13 "${testcvs} watch on" '' - dotest devcom2-14 "${testcvs} edit w5" \ -"${PROG} edit: no such file w5; ignored" - dotest devcom2-15 "${testcvs} editors" '' - dotest devcom2-16 "${testcvs} editors w4" '' - # Make sure there are no droppings lying around - dotest devcom2-17 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \ -"Fw1 _watched= -Fw2 _watched= -Fw3 _watched= -Fnw1 _watched= -D _watched=" - 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 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - devcom3) - # More watch tests, most notably handling of features designed - # for future expansion. - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir 1 - cd 1 - dotest devcom3-1 "${testcvs} -q co first-dir" '' - cd first-dir - - touch w1 w2 - dotest devcom3-2 "${testcvs} add w1 w2" "${DOTSTAR}" - dotest devcom3-3 "${testcvs} watch on w1 w2" '' - dotest devcom3-4 "${testcvs} -q ci -m add-them" "${DOTSTAR}" - - # OK, since we are about to delve into CVS's internals, make - # sure that we seem to be correct about how they work. - dotest devcom3-5 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \ -"Fw1 _watched= -Fw2 _watched=" - # Now write a few more lines, just as if we were a newer version - # of CVS implementing some new feature. - cat <<'EOF' >>${CVSROOT_DIRNAME}/first-dir/CVS/fileattr -Enew line here -G@#$^!@#=& -EOF - # Now get CVS to write to the fileattr file.... - dotest devcom3-6 "${testcvs} watch off w1" '' - # ...and make sure that it hasn't clobbered our new lines. - # Note that writing these lines in another order would be OK - # too. - dotest devcom3-7 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \ -"Fw2 _watched= -G@#..!@#=& -Enew line here" - - # See what CVS does when a file name is duplicated. The - # behavior of all versions of CVS since file attributes were - # implemented is that it nukes the duplications. This seems - # reasonable enough, although it means it isn't clear how - # useful duplicates would be for purposes of future - # expansion. But in the interests of keeping behaviors - # predictable, might as well test for it, I guess. - echo 'Fw2 duplicate=' >>${CVSROOT_DIRNAME}/first-dir/CVS/fileattr - dotest devcom3-8 "${testcvs} watch on w1" '' - dotest devcom3-9 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \ -"Fw2 _watched= -Fw1 _watched= -Enew line here -G@#..!@#=&" - - # Now test disconnected "cvs edit" and the format of the - # CVS/Notify file. - if $remote; then - CVS_SERVER_save=${CVS_SERVER} - CVS_SERVER=${TESTDIR}/cvs-none; export CVS_SERVER - - # The ${DOTSTAR} below matches the exact CVS server error message, - # which in :fork: mode is: - # "$PROG \[edit aborted\]: cannot exec $TESTDIR/cvs-none: ${DOTSTAR}", - # but which is: - # "bash2: line 1: $TESTDIR/cvs-none: No such file or directory" - # when testing across an :ext:/ssh link to my Linux 2.4 box. - # - # I can't even test for the second part of the error message, - # from the client, which varies more consistently, usually either - # "end of file from server" (if the process doing the exec exits - # before the parent gets around to sending data to it) or - # "received broken pipe signal" (if it is the other way around), - # since HP-UX fails to output it. - dotest_fail devcom3-9ar "${testcvs} edit w1 2>/dev/null" - dotest devcom3-9br "test -w w1" "" - dotest devcom3-9cr "cat CVS/Notify" \ -"Ew1 [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] GMT [-a-zA-Z_.0-9]* ${TESTDIR}/1/first-dir EUC" - CVS_SERVER=${CVS_SERVER_save}; export CVS_SERVER - dotest devcom3-9dr "${testcvs} -q update" "" - dotest_fail devcom3-9er "test -f CVS/Notify" "" - dotest devcom3-9fr "${testcvs} watchers w1" \ -"w1 ${username} tedit tunedit tcommit" - dotest devcom3-9gr "${testcvs} unedit w1" "" - dotest devcom3-9hr "${testcvs} watchers w1" "" - fi - - cd ../.. - # OK, now change the tab to a space, and see that CVS gives - # a reasonable error (this is database corruption but CVS should - # not lose its mind). - sed -e 's/Fw2 /Fw2 /' <${CVSROOT_DIRNAME}/first-dir/CVS/fileattr \ - >${CVSROOT_DIRNAME}/first-dir/CVS/fileattr.new - mv ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr.new \ - ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr - mkdir 2; cd 2 - dotest_fail devcom3-10 "${testcvs} -Q co ." \ -"${PROG} \[checkout aborted\]: file attribute database corruption: tab missing in ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" - cd .. - - # Use -f because of the readonly files. - rm -rf 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - watch4) - # More watch tests, including adding directories. - mkdir 1; cd 1 - dotest watch4-0a "${testcvs} -q co -l ." '' - mkdir first-dir - dotest watch4-0b "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - - cd first-dir - dotest watch4-1 "${testcvs} watch on" '' - # This is just like the 173 test - touch file1 - dotest watch4-2 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest watch4-3 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - # Now test the analogous behavior for directories. - mkdir subdir - dotest watch4-4 "${testcvs} add subdir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository" - cd subdir - touch sfile - dotest watch4-5 "${testcvs} add sfile" \ -"${PROG} add: scheduling file .sfile. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest watch4-6 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/subdir/sfile,v -done -Checking in sfile; -${CVSROOT_DIRNAME}/first-dir/subdir/sfile,v <-- sfile -initial revision: 1\.1 -done" - cd ../../.. - mkdir 2; cd 2 - dotest watch4-7 "${testcvs} -q co first-dir" "U first-dir/file1 -U first-dir/subdir/sfile" - dotest_fail watch4-8 "test -w first-dir/file1" '' - dotest_fail watch4-9 "test -w first-dir/subdir/sfile" '' - cd first-dir - dotest watch4-10 "${testcvs} edit file1" '' - echo 'edited in 2' >file1 - cd ../.. - - cd 1/first-dir - dotest watch4-11 "${testcvs} edit file1" '' - echo 'edited in 1' >file1 - dotest watch4-12 "${testcvs} -q ci -m edit-in-1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../.. - cd 2/first-dir - dotest watch4-13 "${testcvs} -q update" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1 and 1\.2 into file1 -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in file1 -C file1" - if (echo yes | ${testcvs} unedit file1) >>${LOGFILE}; then - pass watch4-14 - else - fail watch4-15 - fi - # This could plausibly be defined to either go back to the revision - # which was cvs edit'd (the status quo), or back to revision 1.2 - # (that is, the merge could update CVS/Base/file1). We pick the - # former because it is easier to implement, not because we have - # thought much about which is better. - dotest watch4-16 "cat file1" '' - # Make sure CVS really thinks we are at 1.1. - dotest watch4-17 "${testcvs} -q update" "U file1" - dotest watch4-18 "cat file1" "edited in 1" - cd ../.. - - # As a sanity check, make sure we are in the right place. - dotest watch4-cleanup-1 "test -d 1" '' - dotest watch4-cleanup-1 "test -d 2" '' - # Specify -f because of the readonly files. - rm -rf 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - watch5) - # This test was designed to catch a problem in server - # mode where an 'cvs edit'd file disappeared from the - # CVS/Base directory when 'cvs status' or 'cvs update' - # was called on the file after the file was touched. - # - # This test is still here to prevent the bug from - # being reintroduced. - # - # The rationale for having CVS/Base stay around is that - # CVS/Base should be there if "cvs edit" has been run (this - # may be helpful as a "cvs editors" analogue, it is - # client-side and based on working directory not username; - # but more importantly, it isn't clear why a "cvs status" - # would act like an unedit, and even if it does, it would - # need to make the file read-only again). - - mkdir watch5; cd watch5 - dotest watch5-0a "${testcvs} -q co -l ." '' - mkdir first-dir - dotest watch5-0b "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - - cd first-dir - dotest watch5-1 "${testcvs} watch on" '' - # This is just like the 173 test - touch file1 - dotest watch5-2 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest watch5-3 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - dotest watch5-4 "${testcvs} edit file1" '' - dotest watch5-5 "test -f CVS/Base/file1" '' - if ${testcvs} status file1 >>${LOGFILE} 2>&1; then - pass watch5-6 - else - fail watch5-6 - fi - dotest watch5-7 "test -f CVS/Base/file1" '' - - # Here's where the file used to dissappear - touch file1 - if ${testcvs} status file1 >>${LOGFILE} 2>&1; then - pass watch5-8 - else - fail watch5-8 - fi - dotest watch5-10 "test -f CVS/Base/file1" '' - - # Make sure update won't remove the file either - touch file1 - dotest watch5-11 "${testcvs} -q up" '' - dotest watch5-12 "test -f CVS/Base/file1" '' - - cd ../.. - rm -r watch5 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - - - watch6) - # Check that `cvs watch on' does not reset the fileattr file. - mkdir watch6; cd watch6 - - dotest watch6-setup-1 "$testcvs -Q co -ldtop ." - cd top - mkdir watch6 - dotest watch6-setup-2 "$testcvs -Q add watch6" - - cd .. - dotest watch6-setup-3 "$testcvs -Q co watch6" - cd watch6 - - mkdir subdir - dotest watch6-setup-4 "$testcvs -Q add subdir" - cd subdir - - # START watch add/remove sequence - dotest watch6-1 "$testcvs -Q watch add" - dotest watch6-2 \ -"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null" - - dotest watch6-3 "$testcvs watch on" - dotest watch6-4 \ -"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null" - dotest watch6-5 \ -"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null" - - dotest watch6-6 "$testcvs watch off" - dotest watch6-7 \ -"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null" - dotest_fail watch6-8 \ -"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null" - - dotest watch6-9 "$testcvs watch remove" - dotest_fail watch6-10 \ -"test -d $CVSROOT_DIRNAME/test-directory/subdir/CVS" - dotest_fail watch6-11 \ -"test -f $CVSROOT_DIRNAME/test-directory/subdir/CVS/fileattr" - # END watch add/remove sequence - - echo Hi there >afile - dotest watch6-12 "$testcvs -Q add afile" - dotest watch6-13 "$testcvs ci -m 'A file' afile" \ -"RCS file: $CVSROOT_DIRNAME/watch6/subdir/afile,v -done -Checking in afile; -$CVSROOT_DIRNAME/watch6/subdir/afile,v <-- afile -initial revision: 1\.1 -done" - - # START watch add/remove sequence - dotest watch6-14 "$testcvs -Q watch add" - dotest watch6-15 \ -"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null" - - dotest watch6-16 "$testcvs watch on" - dotest watch6-17 \ -"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null" - dotest watch6-18 \ -"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null" - - dotest watch6-19 "$testcvs watch off" - dotest watch6-20 \ -"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null" - dotest_fail watch6-21 \ -"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null" - - dotest watch6-22 "$testcvs watch remove" - dotest_fail watch6-23 \ -"test -d $CVSROOT_DIRNAME/test-directory/subdir/CVS" - dotest_fail watch6-24 \ -"test -f $CVSROOT_DIRNAME/test-directory/subdir/CVS/fileattr" - # END watch add/remove sequence - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - cd ../../.. - rm -r watch6 - rm -rf $CVSROOT_DIRNAME/watch6 - ;; - - - - unedit-without-baserev) - mkdir 1; cd 1 - module=x - - file=m - echo foo > $file - dotest unedit-without-baserev-1 \ - "$testcvs -Q import -m . $module X Y" '' - dotest unedit-without-baserev-2 "$testcvs -Q co $module" '' - cd $module - - dotest unedit-without-baserev-3 "$testcvs -Q edit $file" '' - - echo add a line >> $file - rm -f CVS/Baserev - - # This will fail on most systems. - 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" - - # SunOS4.1.4 systems make it this far, but with a corrupted - # CVS/Entries file. Demonstrate the corruption! - dotest unedit-without-baserev-5 "cat CVS/Entries" \ - "/$file/1\.1\.1\.1/${DOTSTAR}" - - dotest unedit-without-baserev-6 "${testcvs} -q update" \ -"${PROG} update: warning: m was lost -U m" - - # OK, those were the easy cases. Now tackle the hard one - # (the reason that CVS/Baserev was invented rather than just - # getting the revision from CVS/Entries). This is very - # similar to watch4-10 through watch4-18 but with Baserev - # missing. - cd ../.. - mkdir 2; cd 2 - dotest unedit-without-baserev-7 "${testcvs} -Q co x" '' - cd x - - dotest unedit-without-baserev-10 "${testcvs} edit m" '' - echo 'edited in 2' >m - cd ../.. - - cd 1/x - dotest unedit-without-baserev-11 "${testcvs} edit m" '' - echo 'edited in 1' >m - dotest unedit-without-baserev-12 "${testcvs} -q ci -m edit-in-1" \ -"Checking in m; -${CVSROOT_DIRNAME}/x/m,v <-- m -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../.. - cd 2/x - dotest unedit-without-baserev-13 "${testcvs} -q update" \ -"RCS file: ${CVSROOT_DIRNAME}/x/m,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.2 -Merging differences between 1\.1\.1\.1 and 1\.2 into m -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in m -C m" - rm CVS/Baserev - dotest unedit-without-baserev-14 "echo yes | ${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" - dotest unedit-without-baserev-15 "${testcvs} -q update" \ -"${PROG} update: warning: m was lost -U m" - # The following tests are kind of degenerate compared with - # watch4-16 through watch4-18 but might as well make sure that - # nothing seriously wrong has happened to the working directory. - dotest unedit-without-baserev-16 "cat m" 'edited in 1' - # Make sure CVS really thinks we are at 1.2. - dotest unedit-without-baserev-17 "${testcvs} -q update" "" - dotest unedit-without-baserev-18 "cat m" "edited in 1" - - cd ../.. - rm -rf 1 - rm -r 2 - rm -rf ${CVSROOT_DIRNAME}/$module - ;; - - ignore) - # On Windows, we can't check out CVSROOT, because the case - # insensitivity means that this conflicts with cvsroot. - mkdir ignore - cd ignore - - dotest ignore-1 "${testcvs} -q co CVSROOT" "U CVSROOT/${DOTSTAR}" - cd CVSROOT - echo rootig.c >cvsignore - dotest ignore-2 "${testcvs} add cvsignore" \ -"${PROG}"' add: scheduling file `cvsignore'"'"' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - - # As of Jan 96, local CVS prints "Examining ." and remote doesn't. - # Accept either. - dotest ignore-3 " ${testcvs} ci -m added" \ -"${PROG} [a-z]*: Examining \. -RCS file: ${CVSROOT_DIRNAME}/CVSROOT/cvsignore,v -done -Checking in cvsignore; -${CVSROOT_DIRNAME}/CVSROOT/cvsignore,v <-- cvsignore -initial revision: 1\.1 -done -${PROG} commit: Rebuilding administrative file database" - - cd .. - if echo "yes" | ${testcvs} release -d CVSROOT >>${LOGFILE} ; then - pass ignore-4 - else - fail ignore-4 - fi - - # CVS looks at the home dir from getpwuid, not HOME (is that correct - # behavior?), so this is hard to test and we won't try. - # echo foobar.c >${HOME}/.cvsignore - CVSIGNORE=envig.c; export CVSIGNORE - mkdir dir-to-import - cd dir-to-import - touch foobar.c bar.c rootig.c defig.o envig.c optig.c - # We use sort because we can't predict the order in which - # the files will be listed. - dotest_sort ignore-5 "${testcvs} import -m m -I optig.c ignore/first-dir tag1 tag2" \ -' - -I ignore/first-dir/defig.o -I ignore/first-dir/envig.c -I ignore/first-dir/optig.c -I ignore/first-dir/rootig.c -N ignore/first-dir/bar.c -N ignore/first-dir/foobar.c -No conflicts created by this import' - dotest_sort ignore-6 "${testcvs} import -m m -I ! ignore/second-dir tag3 tag4" \ -' - -N ignore/second-dir/bar.c -N ignore/second-dir/defig.o -N ignore/second-dir/envig.c -N ignore/second-dir/foobar.c -N ignore/second-dir/optig.c -N ignore/second-dir/rootig.c -No conflicts created by this import' - cd .. - rm -r dir-to-import - - mkdir 1 - cd 1 - dotest ignore-7 "${testcvs} -q co -dsecond-dir ignore/second-dir" \ -'U second-dir/bar.c -U second-dir/defig.o -U second-dir/envig.c -U second-dir/foobar.c -U second-dir/optig.c -U second-dir/rootig.c' - dotest ignore-8 "${testcvs} -q co -dfirst-dir ignore/first-dir" 'U first-dir/bar.c -U first-dir/foobar.c' - cd first-dir - touch rootig.c defig.o envig.c optig.c notig.c - dotest ignore-9 "${testcvs} -q update -I optig.c" "${QUESTION} notig.c" - # The fact that CVS requires us to specify -I CVS here strikes me - # as a bug. - dotest_sort ignore-10 "${testcvs} -q update -I ! -I CVS" \ -"${QUESTION} defig.o -${QUESTION} envig.c -${QUESTION} notig.c -${QUESTION} optig.c -${QUESTION} rootig.c" - - # Now test that commands other than update also print "? notig.c" - # where appropriate. Only test this for remote, because local - # CVS only prints it on update. - rm optig.c - if $remote; then - dotest ignore-11r "${testcvs} -q diff" "${QUESTION} notig.c" - - # Force the server to be contacted. Ugh. Having CVS - # contact the server for the sole purpose of checking - # the CVSROOT/cvsignore file does not seem like such a - # good idea, so I imagine this will continue to be - # necessary. Oh well, at least we test CVS's ablity to - # handle a file with a modified timestamp but unmodified - # contents. - touch bar.c - - dotest ignore-11r "${testcvs} -q ci -m commit-it" "${QUESTION} notig.c" - fi - - # now test .cvsignore files - cd .. - echo notig.c >first-dir/.cvsignore - echo foobar.c >second-dir/.cvsignore - touch first-dir/notig.c second-dir/notig.c second-dir/foobar.c - dotest_sort ignore-12 "${testcvs} -qn update" \ -"${QUESTION} first-dir/.cvsignore -${QUESTION} second-dir/.cvsignore -${QUESTION} second-dir/notig.c" - dotest_sort ignore-13 "${testcvs} -qn update -I! -I CVS" \ -"${QUESTION} first-dir/.cvsignore -${QUESTION} first-dir/defig.o -${QUESTION} first-dir/envig.c -${QUESTION} first-dir/rootig.c -${QUESTION} second-dir/.cvsignore -${QUESTION} second-dir/notig.c" - - echo yes | dotest ignore-14 "${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 - echo yes | dotest ignore-15 "${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': " - - cd ../.. - if $keep; then :; else - rm -r ignore - rm -rf ${CVSROOT_DIRNAME}/ignore - fi - ;; - - ignore-on-branch) - # Test that CVS _doesn't_ ignore files on branches because they were - # added to the trunk. - mkdir ignore-on-branch; cd ignore-on-branch - mkdir $CVSROOT_DIRNAME/ignore-on-branch - - # create file1 & file2 on trunk - dotest ignore-on-branch-setup-1 "$testcvs -q co -dsetup ignore-on-branch" '' - cd setup - echo file1 >file1 - dotest ignore-on-branch-setup-2 "$testcvs -q add file1" \ -"${PROG} add: use .${PROG} commit. to add this file permanently" - dotest ignore-on-branch-setup-3 "$testcvs -q ci -mfile1 file1" \ -"RCS file: $CVSROOT_DIRNAME/ignore-on-branch/file1,v -done -Checking in file1; -$CVSROOT_DIRNAME/ignore-on-branch/file1,v <-- file1 -initial revision: 1\.1 -done" - dotest ignore-on-branch-setup-4 "$testcvs -q tag -b branch" 'T file1' - echo file2 >file2 - dotest ignore-on-branch-setup-5 "$testcvs -q add file2" \ -"${PROG} add: use .${PROG} commit. to add this file permanently" - dotest ignore-on-branch-setup-6 "$testcvs -q ci -mtrunk file2" \ -"RCS file: $CVSROOT_DIRNAME/ignore-on-branch/file2,v -done -Checking in file2; -$CVSROOT_DIRNAME/ignore-on-branch/file2,v <-- file2 -initial revision: 1\.1 -done" - - cd .. - - # Check out branch. - # - # - This was the original failure case - file2 would not be flagged - # with a '?' - dotest ignore-on-branch-1 "$testcvs -q co -rbranch ignore-on-branch" \ -'U ignore-on-branch/file1' - cd ignore-on-branch - echo file2 on branch >file2 - dotest ignore-on-branch-2 "$testcvs -nq update" '? file2' - - # Now set up for a join. One of the original fixes for this would - # print out a 'U' and a '?' during a join which added a file. - if $remote; then - dotest ignore-on-branch-3 "$testcvs -q tag -b branch2" \ -'? file2 -T file1' - else - dotest ignore-on-branch-3 "$testcvs -q tag -b branch2" 'T file1' - fi - dotest ignore-on-branch-4 "$testcvs -q add file2" \ -"${PROG} add: use .${PROG} commit. to add this file permanently" - dotest ignore-on-branch-5 "$testcvs -q ci -mbranch file2" \ -"Checking in file2; -$CVSROOT_DIRNAME/ignore-on-branch/file2,v <-- file2 -new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 -done" - dotest ignore-on-branch-6 "$testcvs -q up -rbranch2" \ -"[UP] file1 -$PROG update: file2 is no longer in the repository" - dotest ignore-on-branch-7 "$testcvs -q up -jbranch" 'U file2' - - cd ../.. - if $keep; then :; else - rm -r ignore-on-branch - rm -rf $CVSROOT_DIRNAME/ignore-on-branch - fi - ;; - - binfiles) - # Test cvs's ability to handle binary files. - # List of binary file tests: - # * conflicts, "cvs admin": binfiles - # * branching and joining: binfiles2 - # * adding and removing files: binfiles3 - # * -k wrappers: binwrap, binwrap2, binwrap3 - # * "cvs import" and wrappers: binwrap, binwrap2, binwrap3 - # * -k option to "cvs import": none yet, as far as I know. - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir 1; cd 1 - dotest binfiles-1 "${testcvs} -q co first-dir" '' - ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \ - </dev/null | ${TR} '@' '\000' >binfile.dat - cat binfile.dat binfile.dat >binfile2.dat - cd first-dir - cp ../binfile.dat binfile - dotest binfiles-2 "${testcvs} add -kb binfile" \ -"${PROG}"' add: scheduling file `binfile'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest binfiles-3 "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/binfile,v -done -Checking in binfile; -${CVSROOT_DIRNAME}/first-dir/binfile,v <-- binfile -initial revision: 1\.1 -done" - cd ../.. - mkdir 2; cd 2 - dotest binfiles-4 "${testcvs} -q co first-dir" 'U first-dir/binfile' - cd first-dir - dotest binfiles-5 "cmp ../../1/binfile.dat binfile" '' - # Testing that sticky options is -kb is the closest thing we have - # to testing that binary files work right on non-unix machines - # (until there is automated testing for such machines, of course). - dotest binfiles-5.5 "${testcvs} status binfile" \ -"=================================================================== -File: binfile Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/binfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -kb" - - # Test that "-kk" does not override "-kb" - cd ../.. - mkdir 2a; cd 2a - dotest binfiles-5.5a0 "${testcvs} -q co -kk first-dir" 'U first-dir/binfile' - cd first-dir - # Testing that sticky options is -kb is the closest thing we have - # to testing that binary files work right on non-unix machines - # (until there is automated testing for such machines, of course). - dotest binfiles-5.5a1 "${testcvs} status binfile" \ -"=================================================================== -File: binfile Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/binfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -kb" - - # Test whether the default options from the RCS file are - # also used when operating on files instead of whole - # directories - cd ../.. - mkdir 3; cd 3 - dotest binfiles-5.5b0 "${testcvs} -q co first-dir/binfile" \ -'U first-dir/binfile' - cd first-dir - dotest binfiles-5.5b1 "${testcvs} status binfile" \ -"=================================================================== -File: binfile Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/binfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -kb" - cd ../.. - rm -r 3 - # test that "-kk" does not override "-kb" - mkdir 3; cd 3 - dotest binfiles-5.5c0 "${testcvs} -q co -kk first-dir/binfile" \ -'U first-dir/binfile' - cd first-dir - dotest binfiles-5.5c1 "${testcvs} status binfile" \ -"=================================================================== -File: binfile Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/binfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -kb" - cd ../.. - rm -r 3 - cd 2/first-dir - - cp ../../1/binfile2.dat binfile - dotest binfiles-6 "${testcvs} -q ci -m modify-it" \ -"Checking in binfile; -${CVSROOT_DIRNAME}/first-dir/binfile,v <-- binfile -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../../1/first-dir - dotest binfiles-7 "${testcvs} -q update" '[UP] binfile' - dotest binfiles-8 "cmp ../binfile2.dat binfile" '' - - # Now test handling of conflicts with binary files. - cp ../binfile.dat binfile - dotest binfiles-con0 "${testcvs} -q ci -m modify-it" \ -"Checking in binfile; -${CVSROOT_DIRNAME}/first-dir/binfile,v <-- binfile -new revision: 1\.3; previous revision: 1\.2 -done" - cd ../../2/first-dir - echo 'edits in dir 2' >binfile - dotest binfiles-con1 "${testcvs} -q update" \ -"$PROG update: nonmergeable file needs merge -${PROG} update: revision 1\.3 from repository is now in binfile -${PROG} update: file from working directory is now in \.#binfile\.1\.2 -C binfile" - - dotest_fail binfiles-con1b "$testcvs -q up" "C binfile" - - dotest binfiles-con2 "cmp binfile ../../1/binfile.dat" '' - dotest binfiles-con3 "cat .#binfile.1.2" 'edits in dir 2' - - cp ../../1/binfile2.dat binfile - dotest binfiles-con4 "${testcvs} -q ci -m resolve-it" \ -"Checking in binfile; -${CVSROOT_DIRNAME}/first-dir/binfile,v <-- binfile -new revision: 1\.4; previous revision: 1\.3 -done" - cd ../../1/first-dir - dotest binfiles-con5 "${testcvs} -q update" '[UP] binfile' - - dotest binfiles-9 "${testcvs} -q update -A" '' - # "-kk" no longer does anything with "-kb" - dotest binfiles-10 "${testcvs} -q update -kk" '' - dotest binfiles-11 "${testcvs} -q update" '' - # "-kk" no longer does anything with "-kb" - dotest binfiles-12 "${testcvs} -q update -A" '' - dotest binfiles-13 "${testcvs} -q update -A" '' - - cd ../.. - - mkdir 3 - cd 3 - dotest binfiles-13a0 "${testcvs} -q co -r HEAD first-dir" \ -'U first-dir/binfile' - cd first-dir - dotest binfiles-13a1 "${testcvs} status binfile" \ -"=================================================================== -File: binfile Status: Up-to-date - - Working revision: 1\.4.* - Repository revision: 1\.4 ${CVSROOT_DIRNAME}/first-dir/binfile,v - Sticky Tag: HEAD (revision: 1\.4) - Sticky Date: (none) - Sticky Options: -kb" - cd ../.. - rm -r 3 - - cd 2/first-dir - echo 'this file is $''RCSfile$' >binfile - dotest binfiles-14a "${testcvs} -q ci -m modify-it" \ -"Checking in binfile; -${CVSROOT_DIRNAME}/first-dir/binfile,v <-- binfile -new revision: 1\.5; previous revision: 1\.4 -done" - dotest binfiles-14b "cat binfile" 'this file is $''RCSfile$' - # See binfiles-5.5 for discussion of -kb. - dotest binfiles-14c "${testcvs} status binfile" \ -"=================================================================== -File: binfile Status: Up-to-date - - Working revision: 1\.5.* - Repository revision: 1\.5 ${CVSROOT_DIRNAME}/first-dir/binfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -kb" - dotest binfiles-14d "${testcvs} admin -kv binfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/binfile,v -done" - # cvs admin doesn't change the checked-out file or its sticky - # kopts. There probably should be a way which does (but - # what if the file is modified? And do we try to version - # control the kopt setting?) - dotest binfiles-14e "cat binfile" 'this file is $''RCSfile$' - dotest binfiles-14f "${testcvs} status binfile" \ -"=================================================================== -File: binfile Status: Up-to-date - - Working revision: 1\.5.* - Repository revision: 1\.5 ${CVSROOT_DIRNAME}/first-dir/binfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -kb" - dotest binfiles-14g "${testcvs} -q update -A" '[UP] binfile' - dotest binfiles-14h "cat binfile" 'this file is binfile,v' - dotest binfiles-14i "${testcvs} status binfile" \ -"=================================================================== -File: binfile Status: Up-to-date - - Working revision: 1\.5.* - Repository revision: 1\.5 ${CVSROOT_DIRNAME}/first-dir/binfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -kv" - - # Do sticky options work when used with 'cvs update'? - echo "Not a binary file." > nibfile - dotest binfiles-sticky1 "${testcvs} -q add nibfile" \ -"${PROG} add: use .${PROG} commit. to add this file permanently" - dotest binfiles-sticky2 "${testcvs} -q ci -m add-it nibfile" \ - "RCS file: ${CVSROOT_DIRNAME}/first-dir/nibfile,v -done -Checking in nibfile; -${CVSROOT_DIRNAME}/first-dir/nibfile,v <-- nibfile -initial revision: 1\.1 -done" - dotest binfiles-sticky3 "${testcvs} -q update -kb nibfile" \ - '[UP] nibfile' - dotest binfiles-sticky4 "${testcvs} -q status nibfile" \ -"=================================================================== -File: nibfile Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/nibfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -kb" - - # Now test that -A can clear the sticky option. - dotest binfiles-sticky5 "${testcvs} -q update -A nibfile" \ -"[UP] nibfile" - dotest binfiles-sticky6 "${testcvs} -q status nibfile" \ -"=================================================================== -File: nibfile Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/nibfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest binfiles-15 "${testcvs} -q admin -kb nibfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/nibfile,v -done" - dotest binfiles-16 "${testcvs} -q update nibfile" "[UP] nibfile" - dotest binfiles-17 "${testcvs} -q status nibfile" \ -"=================================================================== -File: nibfile Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/nibfile,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -kb" - - dotest binfiles-o1 "${testcvs} admin -o1.3:: binfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/binfile,v -deleting revision 1\.5 -deleting revision 1\.4 -done" - dotest binfiles-o2 "${testcvs} admin -o::1.3 binfile" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/binfile,v -deleting revision 1\.2 -deleting revision 1\.1 -done" - dotest binfiles-o3 "${testcvs} -q log -h -N binfile" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/binfile,v -Working file: binfile -head: 1\.3 -branch: -locks: strict -access list: -keyword substitution: v -total revisions: 1 -=============================================================================" - - # Check that the contents were right. This isn't the hard case - # (in which RCS_delete_revs does a diff), but might as well. - dotest binfiles-o4 "${testcvs} -q update binfile" "U binfile" - dotest binfiles-o5 "cmp binfile ../../1/binfile.dat" "" - - cd ../.. - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -r 1 - rm -r 2 - ;; - - binfiles2) - # Test cvs's ability to handle binary files, particularly branching - # and joining. The key thing we are worrying about is that CVS - # doesn't print "cannot merge binary files" or some such, in - # situations where no merging is required. - # See also "join" which does this with non-binary files. - # - # Cases (we are merging from the branch to the trunk): - # binfile.dat) File added on branch, not on trunk. - # File should be marked for addition. - # brmod) File modified on branch, not on trunk. - # File should be copied over to trunk (no merging is needed). - # brmod-trmod) File modified on branch, also on trunk. - # This is a conflict. Present the user with both files and - # let them figure it out. - # brmod-wdmod) File modified on branch, not modified in the trunk - # repository, but modified in the (trunk) working directory. - # This is also a conflict. - - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir 1; cd 1 - dotest binfiles2-1 "${testcvs} -q co first-dir" '' - cd first-dir - - # The most important thing here is that binfile, binfile2, &c - # 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 }' \ - </dev/null | ${TR} '@' '\000' >../binfile - cat ../binfile ../binfile >../binfile2 - cat ../binfile2 ../binfile >../binfile3 - - # FIXCVS: unless a branch has at least one file on it, - # tag_check_valid won't know it exists. So if brmod didn't - # exist, we would have to invent it. - cp ../binfile brmod - cp ../binfile brmod-trmod - cp ../binfile brmod-wdmod - dotest binfiles2-1a \ -"${testcvs} add -kb brmod brmod-trmod brmod-wdmod" \ -"${PROG} add: scheduling file .brmod. for addition -${PROG} add: scheduling file .brmod-trmod. for addition -${PROG} add: scheduling file .brmod-wdmod. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest binfiles2-1b "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod,v -done -Checking in brmod; -${CVSROOT_DIRNAME}/first-dir/brmod,v <-- brmod -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v -done -Checking in brmod-trmod; -${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v <-- brmod-trmod -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-wdmod,v -done -Checking in brmod-wdmod; -${CVSROOT_DIRNAME}/first-dir/brmod-wdmod,v <-- brmod-wdmod -initial revision: 1\.1 -done" - dotest binfiles2-2 "${testcvs} -q tag -b br" 'T brmod -T brmod-trmod -T brmod-wdmod' - dotest binfiles2-3 "$testcvs -q update -r br" \ -'U brmod -U brmod-trmod -U brmod-wdmod' - cp ../binfile binfile.dat - dotest binfiles2-4 "${testcvs} add -kb binfile.dat" \ -"${PROG} add: scheduling file .binfile\.dat. for addition on branch .br. -${PROG} add: use .${PROG} commit. to add this file permanently" - cp ../binfile2 brmod - cp ../binfile2 brmod-trmod - cp ../binfile2 brmod-wdmod - dotest binfiles2-5 "${testcvs} -q ci -m br-changes" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/binfile\.dat,v -done -Checking in binfile\.dat; -${CVSROOT_DIRNAME}/first-dir/Attic/binfile\.dat,v <-- binfile\.dat -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in brmod; -${CVSROOT_DIRNAME}/first-dir/brmod,v <-- brmod -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in brmod-trmod; -${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v <-- brmod-trmod -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in brmod-wdmod; -${CVSROOT_DIRNAME}/first-dir/brmod-wdmod,v <-- brmod-wdmod -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - dotest binfiles2-6 "${testcvs} -q update -A" \ -"${PROG} update: binfile\.dat is no longer in the repository -[UP] brmod -[UP] brmod-trmod -[UP] brmod-wdmod" - dotest_fail binfiles2-7 "test -f binfile.dat" '' - dotest binfiles2-7-brmod "cmp ../binfile brmod" - cp ../binfile3 brmod-trmod - dotest binfiles2-7a "${testcvs} -q ci -m tr-modify" \ -"Checking in brmod-trmod; -${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v <-- brmod-trmod -new revision: 1\.2; previous revision: 1\.1 -done" - cp ../binfile3 brmod-wdmod - - dotest binfiles2-8 "${testcvs} -q update -j br" \ -"U binfile\.dat -U brmod -${PROG} update: nonmergeable file needs merge -${PROG} update: revision 1.1.2.1 from repository is now in brmod-trmod -${PROG} update: file from working directory is now in .#brmod-trmod.1.2 -C brmod-trmod -M brmod-wdmod -${PROG} update: nonmergeable file needs merge -${PROG} update: revision 1.1.2.1 from repository is now in brmod-wdmod -${PROG} update: file from working directory is now in .#brmod-wdmod.1.1 -C brmod-wdmod" - - dotest binfiles2-9 "cmp ../binfile binfile.dat" - dotest binfiles2-9-brmod "cmp ../binfile2 brmod" - dotest binfiles2-9-brmod-trmod "cmp ../binfile2 brmod-trmod" - dotest binfiles2-9-brmod-trmod "cmp ../binfile2 brmod-wdmod" - dotest binfiles2-9a-brmod-trmod "cmp ../binfile3 .#brmod-trmod.1.2" - dotest binfiles2-9a-brmod-wdmod "cmp ../binfile3 .#brmod-wdmod.1.1" - - # Test that everything was properly scheduled. - dotest binfiles2-10 "${testcvs} -q ci -m checkin" \ -"Checking in binfile\.dat; -${CVSROOT_DIRNAME}/first-dir/binfile\.dat,v <-- binfile\.dat -new revision: 1\.2; previous revision: 1\.1 -done -Checking in brmod; -${CVSROOT_DIRNAME}/first-dir/brmod,v <-- brmod -new revision: 1\.2; previous revision: 1\.1 -done -Checking in brmod-trmod; -${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v <-- brmod-trmod -new revision: 1\.3; previous revision: 1\.2 -done -Checking in brmod-wdmod; -${CVSROOT_DIRNAME}/first-dir/brmod-wdmod,v <-- brmod-wdmod -new revision: 1\.2; previous revision: 1\.1 -done" - - dotest_fail binfiles2-o1 "${testcvs} -q admin -o :1.2 brmod-trmod" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v -deleting revision 1\.2 -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v: can't remove branch point 1\.1 -${PROG} admin: RCS file for .brmod-trmod. not modified\." - dotest binfiles2-o2 "${testcvs} -q admin -o 1.1.2.1: brmod-trmod" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v -deleting revision 1\.1\.2\.1 -done" - dotest binfiles2-o3 "${testcvs} -q admin -o :1.2 brmod-trmod" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v -deleting revision 1\.2 -deleting revision 1\.1 -done" - dotest binfiles2-o4 "${testcvs} -q log -N brmod-trmod" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v -Working file: brmod-trmod -head: 1\.3 -branch: -locks: strict -access list: -keyword substitution: b -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.3 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -checkin -=============================================================================" - cd .. - cd .. - - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -r 1 - ;; - - binfiles3) - # More binary file tests, especially removing, adding, &c. - # See "binfiles" for a list of binary file tests. - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir 1; cd 1 - dotest binfiles3-1 "${testcvs} -q co first-dir" '' - ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \ - </dev/null | ${TR} '@' '\000' >binfile.dat - cd first-dir - echo hello >file1 - dotest binfiles3-2 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest binfiles3-3 "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - rm file1 - dotest binfiles3-4 "${testcvs} rm file1" \ -"${PROG} remove: scheduling .file1. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest binfiles3-5 "${testcvs} -q ci -m remove-it" \ -"Removing file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: delete; previous revision: 1\.1 -done" - cp ../binfile.dat file1 - dotest binfiles3-6 "${testcvs} add -kb file1" \ -"${PROG} add: Re-adding file .file1. (in place of dead revision 1\.2)\. -${PROG} add: use .${PROG} commit. to add this file permanently" - # The idea behind this test is to make sure that the file - # gets opened in binary mode to send to "cvs ci". - dotest binfiles3-6a "cat CVS/Entries" \ -"/file1/0/[A-Za-z0-9 :]*/-kb/ -D" - # TODO: This just tests the case where the old keyword - # expansion mode is the default (RCS_getexpand == NULL - # in checkaddfile()); should also test the case in which - # we are changing it from one non-default value to another. - dotest binfiles3-7 "${testcvs} -q ci -m readd-it" \ -"${PROG} commit: changing keyword expansion mode to -kb -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 -done" - dotest binfiles3-8 "${testcvs} -q log -h -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.3 -branch: -locks: strict -access list: -keyword substitution: b -total revisions: 3 -=============================================================================" - - # OK, now test admin -o on a binary file. See "admin" - # test for a more complete list of admin -o tests. - cp ${TESTDIR}/1/binfile.dat ${TESTDIR}/1/binfile4.dat - echo '%%$$##@@!!jjiiuull' | ${TR} j '\000' >>${TESTDIR}/1/binfile4.dat - cp ${TESTDIR}/1/binfile4.dat ${TESTDIR}/1/binfile5.dat - echo 'aawwee%$$##@@!!jjil' | ${TR} w '\000' >>${TESTDIR}/1/binfile5.dat - - cp ../binfile4.dat file1 - dotest binfiles3-9 "${testcvs} -q ci -m change" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.4; previous revision: 1\.3 -done" - cp ../binfile5.dat file1 - dotest binfiles3-10 "${testcvs} -q ci -m change" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.5; previous revision: 1\.4 -done" - dotest binfiles3-11 "${testcvs} admin -o 1.3::1.5 file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -deleting revision 1\.4 -done" - dotest binfiles3-12 "${testcvs} -q update -r 1.3 file1" "U file1" - dotest binfiles3-13 "cmp file1 ${TESTDIR}/1/binfile.dat" "" - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - mcopy) - # See comment at "mwrap" test for list of other wrappers tests. - # Test cvs's ability to handle nonmergeable files specified with - # -m 'COPY' in wrappers. Similar to the binfiles2 test, - # which tests the same thing for binary files - # (which are non-mergeable in the same sense). - # - # Cases (we are merging from the branch to the trunk): - # brmod) File modified on branch, not on trunk. - # File should be copied over to trunk (no merging is needed). - # brmod-trmod) File modified on branch, also on trunk. - # This is a conflict. Present the user with both files and - # let them figure it out. - # brmod-wdmod) File modified on branch, not modified in the trunk - # repository, but modified in the (trunk) working directory. - # This is also a conflict. - - # For the moment, remote CVS can't pass wrappers from CVSWRAPPERS - # (see wrap_send). So skip these tests for remote. - if $remote; then :; else - - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir 1; cd 1 - dotest mcopy-1 "${testcvs} -q co first-dir" '' - cd first-dir - - # FIXCVS: unless a branch has at least one file on it, - # tag_check_valid won't know it exists. So if brmod didn't - # exist, we would have to invent it. - echo 'brmod initial contents' >brmod - echo 'brmod-trmod initial contents' >brmod-trmod - echo 'brmod-wdmod initial contents' >brmod-wdmod - echo "* -m 'COPY'" >.cvswrappers - dotest mcopy-1a \ -"${testcvs} add .cvswrappers brmod brmod-trmod brmod-wdmod" \ -"${PROG} add: scheduling file .\.cvswrappers. for addition -${PROG} add: scheduling file .brmod. for addition -${PROG} add: scheduling file .brmod-trmod. for addition -${PROG} add: scheduling file .brmod-wdmod. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest mcopy-1b "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/\.cvswrappers,v -done -Checking in \.cvswrappers; -${CVSROOT_DIRNAME}/first-dir/\.cvswrappers,v <-- \.cvswrappers -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod,v -done -Checking in brmod; -${CVSROOT_DIRNAME}/first-dir/brmod,v <-- brmod -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v -done -Checking in brmod-trmod; -${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v <-- brmod-trmod -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/brmod-wdmod,v -done -Checking in brmod-wdmod; -${CVSROOT_DIRNAME}/first-dir/brmod-wdmod,v <-- brmod-wdmod -initial revision: 1\.1 -done" - - # NOTE: .cvswrappers files are broken (see comment in - # src/wrapper.c). So doing everything via the environment - # variable is a workaround. Better would be to test them - # both. - CVSWRAPPERS="* -m 'COPY'" - export CVSWRAPPERS - dotest mcopy-2 "${testcvs} -q tag -b br" 'T \.cvswrappers -T brmod -T brmod-trmod -T brmod-wdmod' - dotest mcopy-3 "$testcvs -q update -r br" \ -'U .cvswrappers -U brmod -U brmod-trmod -U brmod-wdmod' - echo 'modify brmod on br' >brmod - echo 'modify brmod-trmod on br' >brmod-trmod - echo 'modify brmod-wdmod on br' >brmod-wdmod - dotest mcopy-5 "${testcvs} -q ci -m br-changes" \ -"Checking in brmod; -${CVSROOT_DIRNAME}/first-dir/brmod,v <-- brmod -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in brmod-trmod; -${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v <-- brmod-trmod -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -Checking in brmod-wdmod; -${CVSROOT_DIRNAME}/first-dir/brmod-wdmod,v <-- brmod-wdmod -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - dotest mcopy-6 "$testcvs -q update -A" \ -'U .cvswrappers -U brmod -U brmod-trmod -U brmod-wdmod' - dotest mcopy-7 "cat brmod brmod-trmod brmod-wdmod" \ -"brmod initial contents -brmod-trmod initial contents -brmod-wdmod initial contents" - - echo 'modify brmod-trmod again on trunk' >brmod-trmod - dotest mcopy-7a "${testcvs} -q ci -m tr-modify" \ -"Checking in brmod-trmod; -${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v <-- brmod-trmod -new revision: 1\.2; previous revision: 1\.1 -done" - echo 'modify brmod-wdmod in working dir' >brmod-wdmod - - dotest mcopy-8 "${testcvs} -q update -j br" \ -"U brmod -${PROG} update: nonmergeable file needs merge -${PROG} update: revision 1.1.2.1 from repository is now in brmod-trmod -${PROG} update: file from working directory is now in .#brmod-trmod.1.2 -C brmod-trmod -M brmod-wdmod -${PROG} update: nonmergeable file needs merge -${PROG} update: revision 1.1.2.1 from repository is now in brmod-wdmod -${PROG} update: file from working directory is now in .#brmod-wdmod.1.1 -C brmod-wdmod" - - dotest mcopy-9 "cat brmod brmod-trmod brmod-wdmod" \ -"modify brmod on br -modify brmod-trmod on br -modify brmod-wdmod on br" - dotest mcopy-9a "cat .#brmod-trmod.1.2 .#brmod-wdmod.1.1" \ -"modify brmod-trmod again on trunk -modify brmod-wdmod in working dir" - - # Test that everything was properly scheduled. - dotest mcopy-10 "${testcvs} -q ci -m checkin" \ -"Checking in brmod; -${CVSROOT_DIRNAME}/first-dir/brmod,v <-- brmod -new revision: 1\.2; previous revision: 1\.1 -done -Checking in brmod-trmod; -${CVSROOT_DIRNAME}/first-dir/brmod-trmod,v <-- brmod-trmod -new revision: 1\.3; previous revision: 1\.2 -done -Checking in brmod-wdmod; -${CVSROOT_DIRNAME}/first-dir/brmod-wdmod,v <-- brmod-wdmod -new revision: 1\.2; previous revision: 1\.1 -done" - cd .. - cd .. - - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -r 1 - unset CVSWRAPPERS - - fi # end of tests to be skipped for remote - - ;; - - binwrap) - # Test the ability to specify binary-ness based on file name. - # See "mwrap" for a list of other wrappers tests. - - mkdir dir-to-import - cd dir-to-import - touch foo.c foo.exe - - # While we're here, test for rejection of duplicate tag names. - dotest_fail binwrap-0 \ - "${testcvs} import -m msg -I ! first-dir dup dup" \ -"${PROG} \[[a-z]* aborted\]: tag .dup. was specified more than once" - - if ${testcvs} import -m message -I ! -W "*.exe -k 'b'" \ - first-dir tag1 tag2 >>${LOGFILE}; then - pass binwrap-1 - else - fail binwrap-1 - fi - cd .. - rm -r dir-to-import - dotest binwrap-2 "${testcvs} -q co first-dir" 'U first-dir/foo.c -U first-dir/foo.exe' - dotest binwrap-3 "${testcvs} -q status first-dir" \ -"=================================================================== -File: foo\.c Status: Up-to-date - - Working revision: 1\.1\.1\.1.* - Repository revision: 1\.1\.1\.1 ${CVSROOT_DIRNAME}/first-dir/foo\.c,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: foo\.exe Status: Up-to-date - - Working revision: 1\.1\.1\.1.* - Repository revision: 1\.1\.1\.1 ${CVSROOT_DIRNAME}/first-dir/foo\.exe,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -kb" - rm -r first-dir - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - binwrap2) - # Test the ability to specify binary-ness based on file name. - # See "mwrap" for a list of other wrappers tests. - - mkdir dir-to-import - cd dir-to-import - touch foo.c foo.exe - - # Specify that all files are binary except *.c. - # The order seems to matter, with the earlier rules taking - # precedence. I'm not sure whether that is good or not, - # but it is the current behavior. - if ${testcvs} import -m message -I ! \ - -W "*.c -k 'o'" -W "* -k 'b'" \ - first-dir tag1 tag2 >>${LOGFILE}; then - pass binwrap2-1 - else - fail binwrap2-1 - fi - cd .. - rm -r dir-to-import - dotest binwrap2-2 "${testcvs} -q co first-dir" 'U first-dir/foo.c -U first-dir/foo.exe' - dotest binwrap2-3 "${testcvs} -q status first-dir" \ -"=================================================================== -File: foo\.c Status: Up-to-date - - Working revision: 1\.1\.1\.1.* - Repository revision: 1\.1\.1\.1 ${CVSROOT_DIRNAME}/first-dir/foo\.c,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -ko - -=================================================================== -File: foo\.exe Status: Up-to-date - - Working revision: 1\.1\.1\.1.* - Repository revision: 1\.1\.1\.1 ${CVSROOT_DIRNAME}/first-dir/foo\.exe,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: -kb" - rm -r first-dir - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - binwrap3) - # Test communication of file-specified -k wrappers between - # client and server, in `import': - # - # 1. Set up a directory tree, populate it with files. - # 2. Give each directory a different .cvswrappers file. - # 3. Give the server its own .cvswrappers file. - # 4. Import the whole tree, see if the right files got set - # to binary. - # - # The tree has a top ("0th") level, and two subdirs, sub1/ - # and sub2/; sub2/ contains directory subsub/. Every - # directory has a .cvswrappers file as well as regular - # files. - # - # In the file names, "foo-b.*" should end up binary, and - # "foo-t.*" should end up text. Don't worry about the two - # letter extensions; they're just there to help me keep - # things straight. - # - # Here's the directory tree: - # - # ./ - # .cvswrappers - # foo-b.c0 - # foo-b.sb - # foo-t.c1 - # foo-t.st - # - # sub1/ sub2/ - # .cvswrappers .cvswrappers - # foo-b.c1 foo-b.sb - # foo-b.sb foo-b.st - # foo-t.c0 foo-t.c0 - # foo-t.st foo-t.c1 - # foo-t.c2 - # foo-t.c3 - # - # subsub/ - # .cvswrappers - # foo-b.c3 - # foo-b.sb - # foo-t.c0 - # foo-t.c1 - # foo-t.c2 - # foo-t.st - - binwrap3_line1="This is a test file " - binwrap3_line2="containing little of use " - binwrap3_line3="except this non-haiku" - - binwrap3_text="${binwrap3_line1}${binwrap3_line2}${binwrap3_line3}" - - cd ${TESTDIR} - - # On Windows, we can't check out CVSROOT, because the case - # insensitivity means that this conflicts with cvsroot. - mkdir wnt - cd wnt - - mkdir binwrap3 # the 0th dir - mkdir binwrap3/sub1 - mkdir binwrap3/sub2 - mkdir binwrap3/sub2/subsub - - echo "bar*" > binwrap3/.cvswrappers - echo "*.c0 -k 'b'" >> binwrap3/.cvswrappers - echo "whatever -k 'b'" >> binwrap3/.cvswrappers - echo ${binwrap3_text} > binwrap3/foo-b.c0 - echo ${binwrap3_text} > binwrap3/bar-t.c0 - echo ${binwrap3_text} > binwrap3/foo-b.sb - echo ${binwrap3_text} > binwrap3/foo-t.sb - echo ${binwrap3_text} > binwrap3/foo-t.c1 - echo ${binwrap3_text} > binwrap3/foo-t.st - - echo "bar* -k 'kv'" > binwrap3/sub1/.cvswrappers - echo "*.c1 -k 'b'" >> binwrap3/sub1/.cvswrappers - echo "whatever -k 'b'" >> binwrap3/sub1/.cvswrappers - echo ${binwrap3_text} > binwrap3/sub1/foo-b.c1 - echo ${binwrap3_text} > binwrap3/sub1/bar-t.c1 - echo ${binwrap3_text} > binwrap3/sub1/foo-b.sb - echo ${binwrap3_text} > binwrap3/sub1/foo-t.sb - echo ${binwrap3_text} > binwrap3/sub1/foo-t.c0 - echo ${binwrap3_text} > binwrap3/sub1/foo-t.st - - echo "bar*" > binwrap3/sub2/.cvswrappers - echo "*.st -k 'b'" >> binwrap3/sub2/.cvswrappers - echo ${binwrap3_text} > binwrap3/sub2/foo-b.sb - echo ${binwrap3_text} > binwrap3/sub2/foo-t.sb - echo ${binwrap3_text} > binwrap3/sub2/foo-b.st - echo ${binwrap3_text} > binwrap3/sub2/bar-t.st - echo ${binwrap3_text} > binwrap3/sub2/foo-t.c0 - echo ${binwrap3_text} > binwrap3/sub2/foo-t.c1 - echo ${binwrap3_text} > binwrap3/sub2/foo-t.c2 - echo ${binwrap3_text} > binwrap3/sub2/foo-t.c3 - - echo "bar* -k 'kv'" > binwrap3/sub2/subsub/.cvswrappers - echo "*.c3 -k 'b'" >> binwrap3/sub2/subsub/.cvswrappers - echo "foo -k 'b'" >> binwrap3/sub2/subsub/.cvswrappers - echo "c0* -k 'b'" >> binwrap3/sub2/subsub/.cvswrappers - echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-b.c3 - echo ${binwrap3_text} > binwrap3/sub2/subsub/bar-t.c3 - echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-b.sb - echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-t.sb - echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-t.c0 - echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-t.c1 - echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-t.c2 - echo ${binwrap3_text} > binwrap3/sub2/subsub/foo-t.st - - # Now set up CVSROOT/cvswrappers, the easy way: - dotest binwrap3-1 "${testcvs} -q co CVSROOT" "[UP] CVSROOT${DOTSTAR}" - cd CVSROOT - # This destroys anything currently in cvswrappers, but - # presumably other tests will take care of it themselves if - # they use cvswrappers: - echo "foo-t.sb" > cvswrappers - echo "foo*.sb -k 'b'" >> cvswrappers - dotest binwrap3-2 "${testcvs} -q ci -m cvswrappers-mod" \ -"Checking in cvswrappers; -${CVSROOT_DIRNAME}/CVSROOT/cvswrappers,v <-- cvswrappers -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd .. - - # Avoid environmental interference - CVSWRAPPERS_save=${CVSWRAPPERS} - unset CVSWRAPPERS - - # Do the import - cd binwrap3 - # Not importing .cvswrappers tests whether the client is really - # letting the server know "honestly" whether the file is binary, - # rather than just letting the server see the .cvswrappers file. - dotest binwrap3-2a \ -"${testcvs} import -m . -I .cvswrappers binwrap3 tag1 tag2" \ -"[NI] ${DOTSTAR}" - - # OK, now test "cvs add". - cd .. - rm -r binwrap3 - dotest binwrap3-2b "${testcvs} co binwrap3" "${DOTSTAR}" - cd binwrap3 - cd sub2 - echo "*.newbin -k 'b'" > .cvswrappers - echo .cvswrappers >.cvsignore - echo .cvsignore >>.cvsignore - touch file1.newbin file1.txt - dotest binwrap3-2c "${testcvs} add file1.newbin file1.txt" \ -"${PROG} add: scheduling file .file1\.newbin. for addition -${PROG} add: scheduling file .file1\.txt. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest binwrap3-2d "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/binwrap3/sub2/file1\.newbin,v -done -Checking in file1\.newbin; -${CVSROOT_DIRNAME}/binwrap3/sub2/file1\.newbin,v <-- file1\.newbin -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/binwrap3/sub2/file1\.txt,v -done -Checking in file1\.txt; -${CVSROOT_DIRNAME}/binwrap3/sub2/file1\.txt,v <-- file1\.txt -initial revision: 1\.1 -done" - cd .. - - # Now check out the module and see which files are binary. - cd .. - rm -r binwrap3 - dotest binwrap3-3 "${testcvs} co binwrap3" "${DOTSTAR}" - cd binwrap3 - - # Running "cvs status" and matching output is too - # error-prone, too likely to falsely fail. Instead, we'll - # just grep the Entries lines: - - dotest binwrap3-top1 "grep foo-b.c0 ./CVS/Entries" \ - "/foo-b.c0/1.1.1.1/[A-Za-z0-9 :]*/-kb/" - - dotest binwrap3-top2 "grep foo-b.sb ./CVS/Entries" \ - "/foo-b.sb/1.1.1.1/[A-Za-z0-9 :]*/-kb/" - - dotest binwrap3-top3 "grep foo-t.c1 ./CVS/Entries" \ - "/foo-t.c1/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-top4 "grep foo-t.st ./CVS/Entries" \ - "/foo-t.st/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-top5 "grep foo-t.sb ./CVS/Entries" \ - "/foo-t.sb/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-top6 "grep bar-t.c0 ./CVS/Entries" \ - "/bar-t.c0/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-sub1-1 "grep foo-b.c1 sub1/CVS/Entries" \ - "/foo-b.c1/1.1.1.1/[A-Za-z0-9 :]*/-kb/" - - dotest binwrap3-sub1-2 "grep foo-b.sb sub1/CVS/Entries" \ - "/foo-b.sb/1.1.1.1/[A-Za-z0-9 :]*/-kb/" - - dotest binwrap3-sub1-3 "grep foo-t.c0 sub1/CVS/Entries" \ - "/foo-t.c0/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-sub1-4 "grep foo-t.st sub1/CVS/Entries" \ - "/foo-t.st/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-sub1-5 "grep foo-t.sb sub1/CVS/Entries" \ - "/foo-t.sb/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-sub1-6 "grep bar-t.c1 sub1/CVS/Entries" \ - "/bar-t.c1/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-sub2-1 "grep foo-b.sb sub2/CVS/Entries" \ - "/foo-b.sb/1.1.1.1/[A-Za-z0-9 :]*/-kb/" - - dotest binwrap3-sub2-2 "grep foo-b.st sub2/CVS/Entries" \ - "/foo-b.st/1.1.1.1/[A-Za-z0-9 :]*/-kb/" - - dotest binwrap3-sub2-3 "grep foo-t.c0 sub2/CVS/Entries" \ - "/foo-t.c0/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-sub2-4 "grep foo-t.c1 sub2/CVS/Entries" \ - "/foo-t.c1/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-sub2-5 "grep foo-t.c2 sub2/CVS/Entries" \ - "/foo-t.c2/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-sub2-6 "grep foo-t.c3 sub2/CVS/Entries" \ - "/foo-t.c3/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-sub2-7 "grep foo-t.sb sub2/CVS/Entries" \ - "/foo-t.sb/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-sub2-8 "grep bar-t.st sub2/CVS/Entries" \ - "/bar-t.st/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-subsub1 "grep foo-b.c3 sub2/subsub/CVS/Entries" \ - "/foo-b.c3/1.1.1.1/[A-Za-z0-9 :]*/-kb/" - - dotest binwrap3-subsub2 "grep foo-b.sb sub2/subsub/CVS/Entries" \ - "/foo-b.sb/1.1.1.1/[A-Za-z0-9 :]*/-kb/" - - dotest binwrap3-subsub3 "grep foo-t.c0 sub2/subsub/CVS/Entries" \ - "/foo-t.c0/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-subsub4 "grep foo-t.c1 sub2/subsub/CVS/Entries" \ - "/foo-t.c1/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-subsub5 "grep foo-t.c2 sub2/subsub/CVS/Entries" \ - "/foo-t.c2/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-subsub6 "grep foo-t.st sub2/subsub/CVS/Entries" \ - "/foo-t.st/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-subsub7 "grep foo-t.sb sub2/subsub/CVS/Entries" \ - "/foo-t.sb/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-subsub8 "grep bar-t.c3 sub2/subsub/CVS/Entries" \ - "/bar-t.c3/1.1.1.1/[A-Za-z0-9 :]*//" - - dotest binwrap3-sub2-add1 "grep file1.newbin sub2/CVS/Entries" \ - "/file1.newbin/1.1/[A-Za-z0-9 :]*/-kb/" - dotest binwrap3-sub2-add2 "grep file1.txt sub2/CVS/Entries" \ - "/file1.txt/1.1/[A-Za-z0-9 :]*//" - - # Restore and clean up - cd .. - rm -r binwrap3 CVSROOT - cd .. - rm -r wnt - rm -rf ${CVSROOT_DIRNAME}/binwrap3 - CVSWRAPPERS=${CVSWRAPPERS_save} - ;; - - mwrap) - # Tests of various wrappers features: - # -m 'COPY' and cvs update: mwrap - # -m 'COPY' and joining: mcopy - # -k: binwrap, binwrap2 - # -t/-f: hasn't been written yet. - # - # Tests of different ways of specifying wrappers: - # CVSROOT/cvswrappers: mwrap - # -W: binwrap, binwrap2 - # .cvswrappers in working directory, local: mcopy - # CVSROOT/cvswrappers, .cvswrappers remote: binwrap3 - # CVSWRAPPERS environment variable: mcopy - - # This test is similar to binfiles-con1; -m 'COPY' specifies - # non-mergeableness the same way that -kb does. - - # On Windows, we can't check out CVSROOT, because the case - # insensitivity means that this conflicts with cvsroot. - mkdir wnt - cd wnt - - dotest mwrap-c1 "${testcvs} -q co CVSROOT" "[UP] CVSROOT${DOTSTAR}" - cd CVSROOT - echo "* -m 'COPY'" >>cvswrappers - dotest mwrap-c2 "${testcvs} -q ci -m wrapper-mod" \ -"Checking in cvswrappers; -${CVSROOT_DIRNAME}/CVSROOT/cvswrappers,v <-- cvswrappers -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd .. - mkdir m1; cd m1 - dotest mwrap-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest mwrap-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch aa - dotest mwrap-3 "${testcvs} add aa" \ -"${PROG} add: scheduling file .aa. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest mwrap-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aa,v -done -Checking in aa; -${CVSROOT_DIRNAME}/first-dir/aa,v <-- aa -initial revision: 1\.1 -done" - cd ../.. - mkdir m2; cd m2 - dotest mwrap-5 "${testcvs} -q co first-dir" "U first-dir/aa" - cd first-dir - echo "changed in m2" >aa - dotest mwrap-6 "${testcvs} -q ci -m m2-mod" \ -"Checking in aa; -${CVSROOT_DIRNAME}/first-dir/aa,v <-- aa -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../.. - cd m1/first-dir - echo "changed in m1" >aa - dotest mwrap-7 "$testcvs -nq update" \ -"${PROG} update: nonmergeable file needs merge -${PROG} update: revision 1\.2 from repository is now in aa -${PROG} update: file from working directory is now in \.#aa\.1\.1 -C aa" - dotest mwrap-8 "${testcvs} -q update" \ -"$PROG update: nonmergeable file needs merge -${PROG} update: revision 1\.2 from repository is now in aa -${PROG} update: file from working directory is now in \.#aa\.1\.1 -C aa" - dotest mwrap-9 "cat aa" "changed in m2" - dotest mwrap-10 "cat .#aa.1.1" "changed in m1" - cd ../.. - cd CVSROOT - echo '# comment out' >cvswrappers - dotest mwrap-ce "${testcvs} -q ci -m wrapper-mod" \ -"Checking in cvswrappers; -${CVSROOT_DIRNAME}/CVSROOT/cvswrappers,v <-- cvswrappers -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd .. - rm -r CVSROOT - rm -r m1 m2 - cd .. - rm -r wnt - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - info) - # Administrative file tests. - # Here is a list of where each administrative file is tested: - # loginfo: info - # modules: modules, modules2, modules3 - # cvsignore: ignore - # verifymsg: info - # cvswrappers: mwrap - # taginfo: taginfo - # config: config - - # On Windows, we can't check out CVSROOT, because the case - # insensitivity means that this conflicts with cvsroot. - mkdir wnt - cd wnt - - 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 - echo "ALL echo %{v} >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo - echo "ALL echo %s >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo - echo "ALL echo %{V}AX >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo - echo "first-dir echo %sux >>$TESTDIR/testlog2; cat >/dev/null" \ - >> loginfo - - # Might be nice to move this to crerepos tests; it should - # work to create a loginfo file if you didn't create one - # with "cvs init". - : dotest info-2 "${testcvs} add loginfo" \ -"${PROG}"' add: scheduling file `loginfo'"'"' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - - dotest info-3 "${testcvs} -q ci -m new-loginfo" \ -"Checking in loginfo; -${CVSROOT_DIRNAME}/CVSROOT/loginfo,v <-- loginfo -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd .. - - mkdir ${CVSROOT_DIRNAME}/first-dir - dotest info-5 "${testcvs} -q co first-dir" '' - cd first-dir - touch file1 - dotest info-6 "${testcvs} add file1" \ -"${PROG}"' add: scheduling file `file1'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - echo "cvs -s OTHER=not-this -s MYENV=env-" >>$HOME/.cvsrc - dotest info-6a "${testcvs} -q -s OTHER=value ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -${PROG} commit: loginfo:1: no such user variable \${=ZEE}" - echo line0 >>file1 - dotest info-6b "${testcvs} -q -sOTHER=foo ci -m mod-it" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done -${PROG} commit: 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; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 -done" - cd .. - dotest info-9 "cat $TESTDIR/testlog" "xenv-valueyz=${username}=${CVSROOT_DIRNAME}=" - dotest info-10 "cat $TESTDIR/testlog2" \ -'first-dir file1,NONE,1.1 -first-dir 1.1 -first-dir file1 -first-dir NONEAX -first-dir file1ux -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 - echo '# do nothing' >loginfo - dotest info-11 "${testcvs} -q -s ZEE=garbage ci -m nuke-loginfo" \ -"Checking in loginfo; -${CVSROOT_DIRNAME}/CVSROOT/loginfo,v <-- loginfo -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - - # Now test verifymsg - cat >${TESTDIR}/vscript <<EOF -#!${TESTSHELL} -if sed 1q < \$1 | grep '^BugId:[ ]*[0-9][0-9]*$' > /dev/null; then - exit 0 -elif sed 1q < \$1 | grep '^BugId:[ ]*new$' > /dev/null; then - echo A new bugid was found. >> \$1 - exit 0 -else - echo "No BugId found." - sleep 1 - exit 1 -fi -EOF - cat >${TESTDIR}/vscript2 <<EOF -#!${TESTSHELL} -if test -f CVS/Repository; then - repo=\`cat CVS/Repository\` -else - repo=\`pwd\` -fi -echo \$repo -if echo "\$repo" |grep yet-another/ >/dev/null 2>&1; then - exit 1 -else - exit 0 -fi -EOF - # Grumble, grumble, mumble, search for "Cygwin". - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod +x ${TESTDIR}/vscript*" - else - chmod +x ${TESTDIR}/vscript* - fi - echo "^first-dir/yet-another\\(/\\|\$\\) ${TESTDIR}/vscript2" >>verifymsg - echo "^first-dir\\(/\\|\$\\) ${TESTDIR}/vscript" >>verifymsg - echo "^missing-script\$ ${TESTDIR}/bogus" >>verifymsg - echo "^missing-var\$ ${TESTDIR}/vscript \${=Bogus}" >>verifymsg - # first test the directory independant verifymsg - dotest info-v1 "${testcvs} -q ci -m add-verification" \ -"Checking in verifymsg; -${CVSROOT_DIRNAME}/CVSROOT/verifymsg,v <-- verifymsg -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - - cd ../first-dir - echo line2 >>file1 - dotest_fail info-v2 "${testcvs} -q ci -m bogus" \ -"No BugId found\. -${PROG} \[commit aborted\]: Message verification failed" - - cat >${TESTDIR}/comment.tmp <<EOF -BugId: 42 -and many more lines after it -EOF - dotest info-v3 "${testcvs} -q ci -F ${TESTDIR}/comment.tmp" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.4; previous revision: 1\.3 -done" - rm ${TESTDIR}/comment.tmp - - cd .. - mkdir another-dir - cd another-dir - touch file2 - dotest_fail info-v4 \ - "${testcvs} import -m bogus first-dir/another x y" \ -"No BugId found\. -${PROG} \[import aborted\]: Message verification failed" - - # now verify that directory dependent verifymsgs work - dotest info-v5 \ - "${testcvs} import -m bogus first-dir/yet-another x y" \ -"${TESTDIR}/wnt/another-dir -N first-dir/yet-another/file2 - -No conflicts created by this import" \ -"${CVSROOT_DIRNAME}/first-dir/yet-another -N first-dir/yet-another/file2 - -No conflicts created by this import" - - # FIXMECVS - # - # note that in the local case the error message is the same as - # info-v5 - # - # This means that the verifymsg scripts cannot reliably and - # consistantly obtain information on which directory is being - # committed to. Thus it is currently useless for them to be - # running in every dir. They should either be run once or - # directory information should be passed. - if $remote; then - dotest_fail info-v6r \ - "${testcvs} import -m bogus first-dir/yet-another/and-another x y" \ -"${CVSROOT_DIRNAME}/first-dir/yet-another/and-another -${PROG} \[import aborted\]: Message verification failed" - else - dotest info-v6 \ - "${testcvs} import -m bogus first-dir/yet-another/and-another x y" \ -"${TESTDIR}/wnt/another-dir -N first-dir/yet-another/and-another/file2 - -No conflicts created by this import" - fi - - # check that errors invoking the script cause verification failure - # - # The second text below occurs on Cygwin, where I assume execvp - # does not return to let CVS print the error message when its - # argument does not exist. - dotest_fail info-v7 "${testcvs} import -m bogus missing-script x y" \ -"${PROG} import: cannot exec ${TESTDIR}/bogus: No such file or directory -${PROG} \[import aborted\]: Message verification failed" \ -"${PROG} \[import aborted\]: Message verification failed" - - dotest_fail info-v8 "${testcvs} import -m bogus missing-var x y" \ -"${PROG} import: verifymsg:25: no such user variable \${=Bogus} -${PROG} \[import aborted\]: Message verification failed" - - rm file2 - cd .. - rmdir another-dir - - cd CVSROOT - echo "RereadLogAfterVerify=always" >>config - dotest info-rereadlog-1 "${testcvs} -q ci -m add-RereadLogAfterVerify=always" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../first-dir - echo line3 >>file1 - cat >${TESTDIR}/comment.tmp <<EOF -BugId: new -See what happens next. -EOF - dotest info-reread-2 "${testcvs} -q ci -F ${TESTDIR}/comment.tmp" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.5; previous revision: 1\.4 -done" - dotest info-reread-3 "${testcvs} -q log -N -r1.5 file1" " -.* -BugId: new -See what happens next. -A new bugid was found. -=============================================================================" - - cd ../CVSROOT - grep -v "RereadLogAfterVerify" config > config.new - mv config.new config - echo "RereadLogAfterVerify=stat" >>config - dotest info-reread-4 "${testcvs} -q ci -m add-RereadLogAfterVerify=stat" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../first-dir - echo line4 >>file1 - cat >${TESTDIR}/comment.tmp <<EOF -BugId: new -See what happens next with stat. -EOF - dotest info-reread-5 "${testcvs} -q ci -F ${TESTDIR}/comment.tmp" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.6; previous revision: 1\.5 -done" - dotest info-reread-6 "${testcvs} -q log -N -r1.6 file1" " -.* -BugId: new -See what happens next with stat. -A new bugid was found. -=============================================================================" - - cd ../CVSROOT - grep -v "RereadLogAfterVerify" config > config.new - mv config.new config - echo "RereadLogAfterVerify=never" >>config - dotest info-reread-7 "${testcvs} -q ci -m add-RereadLogAfterVerify=never" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../first-dir - echo line5 >>file1 - cat >${TESTDIR}/comment.tmp <<EOF -BugId: new -See what happens next. -EOF - dotest info-reread-8 "${testcvs} -q ci -F ${TESTDIR}/comment.tmp" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.7; previous revision: 1\.6 -done" - dotest info-reread-6 "${testcvs} -q log -N -r1.7 file1" " -.* -BugId: new -See what happens next. -=============================================================================" - - cd ../CVSROOT - echo 'DEFAULT false' >verifymsg - echo 'DEFAULT true' >>verifymsg - echo '# defaults' >config - dotest info-multdef "${testcvs} -q ci -m multdef" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -Checking in verifymsg; -${CVSROOT_DIRNAME}/CVSROOT/verifymsg,v <-- verifymsg -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - - cd ../CVSROOT - echo '# do nothing' >verifymsg - dotest info-cleanup-verifymsg "${testcvs} -q ci -m nuke-verifymsg" \ -"${PROG} commit: Multiple .DEFAULT. lines (1 and 2) in verifymsg file -Checking in verifymsg; -${CVSROOT_DIRNAME}/CVSROOT/verifymsg,v <-- verifymsg -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - rm ${TESTDIR}/vscript* - cd .. - - dotest_fail info-cleanup-0 "${testcvs} -n release -d CVSROOT" \ -"${PROG} \[release aborted\]: cannot run command ${DOTSTAR}" - - if echo "yes" | ${testcvs} release -d CVSROOT >>${LOGFILE} ; then - pass info-cleanup - else - fail info-cleanup - fi - if echo "yes" | ${testcvs} release -d first-dir >>${LOGFILE} ; then - pass info-cleanup-2 - else - fail info-cleanup-2 - fi - cd .. - rm -r wnt - rm $HOME/.cvsrc - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - taginfo) - # Tests of the CVSROOT/taginfo file. See the comment at the - # "info" tests for a full list of administrative file tests. - - # Tests to add: - # -F to move - - mkdir 1; cd 1 - dotest taginfo-1 "${testcvs} -q co CVSROOT" "U CVSROOT/${DOTSTAR}" - cd CVSROOT - cat >${TESTDIR}/1/loggit <<EOF -#!${TESTSHELL} -if test "\$1" = rejectme; then - exit 1 -else - echo "\$@" >>${TESTDIR}/1/taglog - exit 0 -fi -EOF - # #^@&!^@ Cygwin. - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod +x ${TESTDIR}/1/loggit" - else - chmod +x ${TESTDIR}/1/loggit - fi - echo "ALL ${TESTDIR}/1/loggit" >taginfo - dotest taginfo-2 "${testcvs} -q ci -m check-in-taginfo" \ -"Checking in taginfo; -${CVSROOT_DIRNAME}/CVSROOT/taginfo,v <-- taginfo -new revision: 1\.2; previous revision: 1\.1 -done -${PROG} commit: Rebuilding administrative file database" - cd .. - - # taginfo-3 used to rely on the top-level CVS directory - # being created to add "first-dir" to the repository. Since - # that won't happen anymore, we create the directory in the - # repository. - mkdir ${CVSROOT_DIRNAME}/first-dir - dotest taginfo-3 "${testcvs} -q co first-dir" '' - - cd first-dir - echo first >file1 - dotest taginfo-4 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest taginfo-5 "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - dotest taginfo-6 "${testcvs} -q tag tag1" "T file1" - dotest taginfo-7 "${testcvs} -q tag -b br" "T file1" - dotest taginfo-8 "$testcvs -q update -r br" '[UP] file1' - echo add text on branch >>file1 - dotest taginfo-9 "${testcvs} -q ci -m modify-on-br" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - dotest taginfo-10 "${testcvs} -q tag -F -c brtag" "T file1" - - dotest_fail taginfo-11 "${testcvs} -q tag rejectme" \ -"${PROG} tag: Pre-tag check failed -${PROG} \[tag aborted\]: correct the above errors first!" - - # When we are using taginfo to allow/disallow, it would be - # convenient to be able to use "cvs -n tag" to test whether - # the allow/disallow functionality is working as expected. - dotest taginfo-12 "${testcvs} -nq tag rejectme" "T file1" - - # But when taginfo is used for logging, it is a pain for -n - # to call taginfo, since taginfo doesn't know whether -n was - # specified or not. - dotest taginfo-13 "${testcvs} -nq tag would-be-tag" "T file1" - - # Deleting: the cases are basically either the tag existed, - # or it didn't exist. - dotest taginfo-14 "${testcvs} -q tag -d tag1" "D file1" - dotest taginfo-15 "${testcvs} -q tag -d tag1" "" - - # Likewise with rtag. - dotest taginfo-16 "${testcvs} -q rtag tag1 first-dir" "" - dotest taginfo-17 "${testcvs} -q rtag -d tag1 first-dir" "" - dotest taginfo-18 "${testcvs} -q rtag -d tag1 first-dir" "" - - # The "br" example should be passing 1.1.2 or 1.1.0.2. - # But it turns out that is very hard to implement, since - # check_fileproc doesn't know what branch number it will - # get. Probably the whole thing should be re-architected - # so that taginfo only allows/denies tagging, and a new - # hook, which is done from tag_fileproc, does logging. - # That would solve this, some more subtle races, and also - # the fact that it is nice for users to run "-n tag foo" to - # see whether a tag would be allowed. Failing that, - # I suppose passing "1.1.branch" or "branch" for "br" - # would be an improvement. - dotest taginfo-examine "cat ${TESTDIR}/1/taglog" \ -"tag1 add ${CVSROOT_DIRNAME}/first-dir file1 1.1 -br add ${CVSROOT_DIRNAME}/first-dir file1 1.1 -brtag mov ${CVSROOT_DIRNAME}/first-dir file1 1.1.2.1 -tag1 del ${CVSROOT_DIRNAME}/first-dir file1 1.1 -tag1 del ${CVSROOT_DIRNAME}/first-dir -tag1 add ${CVSROOT_DIRNAME}/first-dir file1 1.1 -tag1 del ${CVSROOT_DIRNAME}/first-dir file1 1.1 -tag1 del ${CVSROOT_DIRNAME}/first-dir" - - cd .. - cd CVSROOT - echo '# Keep life simple' > taginfo - dotest taginfo-cleanup-1 "${testcvs} -q ci -m check-in-taginfo" \ -"Checking in taginfo; -${CVSROOT_DIRNAME}/CVSROOT/taginfo,v <-- taginfo -new revision: 1\.3; previous revision: 1\.2 -done -${PROG} commit: Rebuilding administrative file database" - cd .. - cd .. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - config) - # Tests of the CVSROOT/config file. See the comment at the - # "info" tests for a full list of administrative file tests. - - # On Windows, we can't check out CVSROOT, because the case - # insensitivity means that this conflicts with cvsroot. - mkdir wnt - cd wnt - - dotest config-1 "${testcvs} -q co CVSROOT" "U CVSROOT/${DOTSTAR}" - cd CVSROOT - echo 'bogus line' >config - # We can't rely on specific revisions, since other tests - # might need to modify CVSROOT/config - dotest config-3 "${testcvs} -q ci -m change-to-bogus-line" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - echo 'BogusOption=yes' >config - dotest config-4 "${testcvs} -q ci -m change-to-bogus-opt" \ -"${PROG} [a-z]*: syntax error in ${CVSROOT_DIRNAME}/CVSROOT/config: line 'bogus line' is missing '=' -Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - echo '# No config is a good config' > config - dotest config-5 "${testcvs} -q ci -m change-to-comment" \ -"${PROG} [a-z]*: ${CVSROOT_DIRNAME}/CVSROOT/config: unrecognized keyword 'BogusOption' -Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - dotest config-6 "${testcvs} -q update" '' - echo 'IgnoreUnknownConfigKeys=yes' > config - echo 'BogusOption=yes' >> config - dotest config-7 "${testcvs} -q ci -m change-to-comment" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - dotest config-8 "${testcvs} -q update" '' - echo '# No config is a good config' > config - dotest config-9 "${testcvs} -q ci -m change-to-comment" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - dotest config-10 "${testcvs} -q update" '' - - cd .. - rm -r CVSROOT - cd .. - rm -r wnt - ;; - - serverpatch) - # Test remote CVS handling of unpatchable files. This isn't - # much of a test for local CVS. - # We test this with some keyword expansion games, but the situation - # also arises if the user modifies the file while CVS is running. - mkdir ${CVSROOT_DIRNAME}/first-dir - mkdir 1 - cd 1 - dotest serverpatch-1 "${testcvs} -q co first-dir" '' - - cd first-dir - - # Add a file with an RCS keyword. - echo '$''Name$' > file1 - echo '1' >> file1 - dotest serverpatch-2 "${testcvs} add file1" \ -"${PROG}"' add: scheduling file `file1'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - - dotest serverpatch-3 "${testcvs} -q commit -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - - # Tag the file. - dotest serverpatch-4 "${testcvs} -q tag tag file1" 'T file1' - - # Check out a tagged copy of the file. - cd ../.. - mkdir 2 - cd 2 - dotest serverpatch-5 "${testcvs} -q co -r tag first-dir" \ -'U first-dir/file1' - - # Remove the tag. Prior to 1.11.23, this left the tag string in the - # expansion of the Name keyword. - dotest serverpatch-6 "$testcvs -q update -A first-dir" \ -'U first-dir/file1' - - # Modify and check in the first copy. - cd ../1/first-dir - echo '2' >> file1 - dotest serverpatch-7 "${testcvs} -q ci -mx file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - - # Now update the second copy. Prior to 1.11.23, the patch would fail - # using remote CVS, forcing the file to be refetched. - cd ../../2/first-dir - dotest serverpatch-8 "${testcvs} -q update" \ -'[UP] file1' - - cd ../.. - rm -r 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - log) - # Test selecting revisions with cvs log. - # See also log2 tests for more tests. - # See also branches-14.3 for logging with a branch off of a branch. - # See also multibranch-14 for logging with several branches off the - # same branchpoint. - # Tests of each option to cvs log: - # -h: admin-19a-log - # -N: log, log2, admin-19a-log - # -b, -r: log - # -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 - dotest log-1 "${testcvs} -q co first-dir" '' - cd first-dir - echo 'first revision' > file1 - echo 'first revision' > file2 - dotest log-2 "${testcvs} add file1 file2" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - - # While we're at it, check multi-line comments, input from file, - # and trailing whitespace trimming - echo 'line 1 ' >${TESTDIR}/comment.tmp - echo ' ' >>${TESTDIR}/comment.tmp - echo 'line 2 ' >>${TESTDIR}/comment.tmp - echo ' ' >>${TESTDIR}/comment.tmp - echo ' ' >>${TESTDIR}/comment.tmp - dotest log-3 "${testcvs} -q commit -F ${TESTDIR}/comment.tmp" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - rm -f ${TESTDIR}/comment.tmp - - echo 'second revision' > file1 - echo 'second revision' > file2 - dotest log-4 "${testcvs} -q ci -m2 file1 file2" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.2; previous revision: 1\.1 -done" - - dotest log-5 "${testcvs} -q tag -b branch file1" 'T file1' - dotest log-5a "${testcvs} -q tag tag1 file2" 'T file2' - - echo 'third revision' > file1 - echo 'third revision' > file2 - dotest log-6 "${testcvs} -q ci -m3 file1 file2" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.3; previous revision: 1\.2 -done" - - dotest log-6a "${testcvs} -q tag tag2 file2" 'T file2' - - dotest log-7 "${testcvs} -q update -r branch" \ -"[UP] file1 -${PROG} update: file2 is no longer in the repository" - - echo 'first branch revision' > file1 - dotest log-8 "${testcvs} -q ci -m1b file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2\.2\.1; previous revision: 1\.2 -done" - - dotest log-9 "${testcvs} -q tag tag file1" 'T file1' - - echo 'second branch revision' > file1 - dotest log-10 "${testcvs} -q ci -m2b file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2\.2\.2; previous revision: 1\.2\.2\.1 -done" - - # Set up a bunch of shell variables to make the later tests - # easier to describe.= - log_header1=" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.3 -branch: -locks: strict -access list:" - rlog_header1=" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -head: 1\.3 -branch: -locks: strict -access list:" - log_tags1='symbolic names: - tag: 1\.2\.2\.1 - branch: 1\.2\.0\.2' - log_keyword='keyword substitution: kv' - log_dash='---------------------------- -revision' - log_date="date: [0-9/]* [0-9:]*; author: ${username}; state: Exp;" - log_lines=" lines: ${PLUS}1 -1" - log_rev1="${log_dash} 1\.1 -${log_date} -line 1 - -line 2" - log_rev2="${log_dash} 1\.2 -${log_date}${log_lines} -branches: 1\.2\.2; -2" - log_rev3="${log_dash} 1\.3 -${log_date}${log_lines} -3" - log_rev1b="${log_dash} 1\.2\.2\.1 -${log_date}${log_lines} -1b" - log_rev2b="${log_dash} 1\.2\.2\.2 -${log_date}${log_lines} -2b" - log_trailer='=============================================================================' - - # Now, finally, test the log output. - - dotest log-11 "${testcvs} log file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 5 -description: -${log_rev3} -${log_rev2} -${log_rev1} -${log_rev2b} -${log_rev1b} -${log_trailer}" - - dotest log-12 "${testcvs} log -N file1" \ -"${log_header1} -${log_keyword} -total revisions: 5; selected revisions: 5 -description: -${log_rev3} -${log_rev2} -${log_rev1} -${log_rev2b} -${log_rev1b} -${log_trailer}" - - dotest log-13 "${testcvs} log -b file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 3 -description: -${log_rev3} -${log_rev2} -${log_rev1} -${log_trailer}" - - dotest log-14 "${testcvs} log -r file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - - dotest log-14a "${testcvs} log -rHEAD file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -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} log: nothing known about HEAD -${log_header1} -${log_tags1} -${log_keyword} -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_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - dotest log-14d "${testcvs} log -r, file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - dotest log-14e "${testcvs} log -r. file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - dotest log-14f "${testcvs} log -r:: file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 0 -description: -${log_trailer}" - - dotest log-15 "${testcvs} log -r1.2 file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev2} -${log_trailer}" - - dotest log-16 "${testcvs} log -r1.2.2 file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer}" - - # This test would fail with the old invocation of rlog, but it - # works with the builtin log support. - dotest log-17 "${testcvs} log -rbranch file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer}" - - dotest log-18 "${testcvs} log -r1.2.2. file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -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_header1} -${log_tags1} -${log_keyword} -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" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev2b} -${log_trailer}" - - dotest log-20 "${testcvs} log -r1.2: file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev3} -${log_rev2} -${log_trailer}" - - dotest log-20a "${testcvs} log -r1.2:: file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - - dotest log-21 "${testcvs} log -r:1.2 file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev2} -${log_rev1} -${log_trailer}" - - dotest log-21a "${testcvs} log -r::1.2 file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev2} -${log_rev1} -${log_trailer}" - - dotest log-22 "${testcvs} log -r1.1:1.2 file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev2} -${log_rev1} -${log_trailer}" - - dotest log-22a "${testcvs} log -r1.1::1.2 file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev2} -${log_trailer}" - - dotest log-22b "${testcvs} log -r1.1::1.3 file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev3} -${log_rev2} -${log_trailer}" - - # Test BASE pseudotag - dotest log-23 "${testcvs} log -rBASE file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev2b} -${log_trailer}" - - dotest log-24 "${testcvs} -q up -r1.2 file1" "[UP] file1" - dotest log-25 "${testcvs} log -rBASE file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev2} -${log_trailer}" - - dotest log-26 "${testcvs} -q up -rbranch file1" "[UP] file1" - - # Now the same tests but with rlog - - dotest log-r11 "${testcvs} rlog first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 5 -description: -${log_rev3} -${log_rev2} -${log_rev1} -${log_rev2b} -${log_rev1b} -${log_trailer}" - - dotest log-r12 "${testcvs} rlog -N first-dir/file1" \ -"${rlog_header1} -${log_keyword} -total revisions: 5; selected revisions: 5 -description: -${log_rev3} -${log_rev2} -${log_rev1} -${log_rev2b} -${log_rev1b} -${log_trailer}" - - dotest log-r13 "${testcvs} rlog -b first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 3 -description: -${log_rev3} -${log_rev2} -${log_rev1} -${log_trailer}" - - dotest log-r14 "${testcvs} rlog -r first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - - dotest log-r14a "${testcvs} rlog -rHEAD first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - - dotest_fail log-r14b "${testcvs} rlog -r HEAD first-dir/file1" \ -"${PROG} rlog: cannot find module .HEAD. - ignored -${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - - dotest log-r14c "${testcvs} rlog -r: first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - dotest log-r14d "${testcvs} rlog -r, first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - dotest log-r14e "${testcvs} rlog -r. first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - dotest log-r14f "${testcvs} rlog -r:: first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 0 -description: -${log_trailer}" - - dotest log-r15 "${testcvs} rlog -r1.2 first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev2} -${log_trailer}" - - dotest log-r16 "${testcvs} rlog -r1.2.2 first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer}" - - dotest log-r17 "${testcvs} rlog -rbranch first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer}" - - dotest log-r18 "${testcvs} rlog -r1.2.2. first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev2b} -${log_trailer}" - - dotest log-r18a "${testcvs} rlog -r1.2.2.2 -r1.3:1.3 first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev3} -${log_rev2b} -${log_trailer}" - - dotest log-r19 "${testcvs} rlog -rbranch. first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev2b} -${log_trailer}" - - dotest log-r20 "${testcvs} rlog -r1.2: first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev3} -${log_rev2} -${log_trailer}" - - dotest log-r20a "${testcvs} rlog -r1.2:: first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev3} -${log_trailer}" - - dotest log-r21 "${testcvs} rlog -r:1.2 first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev2} -${log_rev1} -${log_trailer}" - - dotest log-r21a "${testcvs} rlog -r::1.2 first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev2} -${log_rev1} -${log_trailer}" - - dotest log-r22 "${testcvs} rlog -r1.1:1.2 first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev2} -${log_rev1} -${log_trailer}" - - dotest log-r22a "${testcvs} rlog -r1.1::1.2 first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 1 -description: -${log_rev2} -${log_trailer}" - - dotest log-r22b "${testcvs} rlog -r1.1::1.3 first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 2 -description: -${log_rev3} -${log_rev2} -${log_trailer}" - - # Test BASE pseudotag - dotest log-r23 "${testcvs} rlog -rBASE first-dir/file1" \ -"${PROG} rlog: warning: no revision .BASE. in .${CVSROOT_DIRNAME}/first-dir/file1,v. -${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 0 -description: -${log_trailer}" - - dotest log-r24 "${testcvs} -q up -r1.2 file1" "[UP] file1" - dotest log-r25 "${testcvs} rlog -rBASE first-dir/file1" \ -"${PROG} rlog: warning: no revision .BASE. in .${CVSROOT_DIRNAME}/first-dir/file1,v. -${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 0 -description: -${log_trailer}" - - # Test when head is dead - - dotest log-d0 "${testcvs} -q up -A" \ -"[UP] file1 -U file2" - dotest log-d1 "${testcvs} -q rm -f file1" \ -"${PROG} remove: use .${PROG} commit. to remove this file permanently" - dotest log-d2 "${testcvs} -q ci -m4" \ -"Removing file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: delete; previous revision: 1\.3 -done" - - log_header1=" -RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -Working file: file1 -head: 1\.4 -branch: -locks: strict -access list:" - rlog_header1=" -RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -head: 1\.4 -branch: -locks: strict -access list:" - log_header2=" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -Working file: file2 -head: 1\.3 -branch: -locks: strict -access list:" - rlog_header2=" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -head: 1\.3 -branch: -locks: strict -access list:" - log_tags2='symbolic names: - tag2: 1\.3 - tag1: 1\.2' - log_rev4="${log_dash} 1\.4 -date: [0-9/]* [0-9:]*; author: ${username}; state: dead; lines: ${PLUS}0 -0 -4" - log_rev22="${log_dash} 1\.2 -${log_date}${log_lines} -2" - - dotest log-d3 "${testcvs} log -rbranch file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer}" - dotest log-rd3 "${testcvs} rlog -rbranch first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer}" - dotest log-d4 "${testcvs} -q log -rbranch" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer} -${PROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v. -${log_header2} -${log_tags2} -${log_keyword} -total revisions: 3; selected revisions: 0 -description: -${log_trailer}" - dotest log-d4a "${testcvs} -q log -t -rbranch" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 6 -description: -${log_trailer} -${PROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v. -${log_header2} -${log_tags2} -${log_keyword} -total revisions: 3 -description: -${log_trailer}" - dotest log-d4b "${testcvs} -q log -tS -rbranch" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_trailer} -${PROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v." - dotest log-d4c "${testcvs} -q log -h -rbranch" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 6 -${log_trailer} -${PROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v. -${log_header2} -${log_tags2} -${log_keyword} -total revisions: 3 -${log_trailer}" - dotest log-d4d "${testcvs} -q log -hS -rbranch" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -${log_trailer} -${PROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v." - dotest log-d4e "${testcvs} -q log -R -rbranch" \ -"${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -${CVSROOT_DIRNAME}/first-dir/file2,v" - dotest log-d4f "${testcvs} -q log -R -S -rbranch" \ -"${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -${PROG} log: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v." - dotest log-rd4 "${testcvs} -q rlog -rbranch first-dir" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer} -${PROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v. -${rlog_header2} -${log_tags2} -${log_keyword} -total revisions: 3; selected revisions: 0 -description: -${log_trailer}" - dotest log-rd4a "${testcvs} -q rlog -t -rbranch first-dir" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 6 -description: -${log_trailer} -${PROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v. -${rlog_header2} -${log_tags2} -${log_keyword} -total revisions: 3 -description: -${log_trailer}" - dotest log-rd4b "${testcvs} -q rlog -St -rbranch first-dir" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_trailer} -${PROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v." - dotest log-rd4c "${testcvs} -q rlog -h -rbranch first-dir" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 6 -${log_trailer} -${PROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v. -${rlog_header2} -${log_tags2} -${log_keyword} -total revisions: 3 -${log_trailer}" - dotest log-rd4d "${testcvs} -q rlog -Sh -rbranch first-dir" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -${log_trailer} -${PROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v." - dotest log-rd4e "${testcvs} -q rlog -R -rbranch first-dir" \ -"${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -${CVSROOT_DIRNAME}/first-dir/file2,v" - dotest log-rd4f "${testcvs} -q rlog -R -S -rbranch first-dir" \ -"${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -${PROG} rlog: warning: no revision .branch. in .${CVSROOT_DIRNAME}/first-dir/file2,v." - dotest log-d5 "${testcvs} log -r1.2.2.1:1.2.2.2 file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer}" - dotest log-rd5 "${testcvs} rlog -r1.2.2.1:1.2.2.2 first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer}" - dotest log-d6 "${testcvs} -q log -r1.2.2.1:1.2.2.2" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer} -${log_header2} -${log_tags2} -${log_keyword} -total revisions: 3; selected revisions: 0 -description: -${log_trailer}" - dotest log-rd6 "${testcvs} -q rlog -r1.2.2.1:1.2.2.2 first-dir" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_rev2b} -${log_rev1b} -${log_trailer} -${rlog_header2} -${log_tags2} -${log_keyword} -total revisions: 3; selected revisions: 0 -description: -${log_trailer}" - dotest log-d7 "${testcvs} log -r1.2:1.3 file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_rev3} -${log_rev2} -${log_trailer}" - dotest log-rd7 "${testcvs} -q rlog -r1.2:1.3 first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 2 -description: -${log_rev3} -${log_rev2} -${log_trailer}" - dotest log-d8 "${testcvs} -q log -rtag1:tag2" \ -"${PROG} log: warning: no revision .tag1. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v. -${PROG} log: warning: no revision .tag2. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v. -${log_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 0 -description: -${log_trailer} -${log_header2} -${log_tags2} -${log_keyword} -total revisions: 3; selected revisions: 2 -description: -${log_rev3} -${log_rev22} -${log_trailer}" - dotest log-d8a "${testcvs} -q log -rtag1:tag2 -S" \ -"${PROG} log: warning: no revision .tag1. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v. -${PROG} log: warning: no revision .tag2. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v. -${log_header2} -${log_tags2} -${log_keyword} -total revisions: 3; selected revisions: 2 -description: -${log_rev3} -${log_rev22} -${log_trailer}" - dotest log-rd8 "${testcvs} -q rlog -rtag1:tag2 first-dir" \ -"${PROG} rlog: warning: no revision .tag1. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v. -${PROG} rlog: warning: no revision .tag2. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v. -${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 6; selected revisions: 0 -description: -${log_trailer} -${rlog_header2} -${log_tags2} -${log_keyword} -total revisions: 3; selected revisions: 2 -description: -${log_rev3} -${log_rev22} -${log_trailer}" - dotest log-rd8a "${testcvs} -q rlog -rtag1:tag2 -S first-dir" \ -"${PROG} rlog: warning: no revision .tag1. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v. -${PROG} rlog: warning: no revision .tag2. in .${CVSROOT_DIRNAME}/first-dir/Attic/file1,v. -${rlog_header2} -${log_tags2} -${log_keyword} -total revisions: 3; selected revisions: 2 -description: -${log_rev3} -${log_rev22} -${log_trailer}" - - dotest log-d99 "${testcvs} -q up -rbranch" \ -"[UP] file1 -${PROG} update: file2 is no longer in the repository" - - # Now test outdating revisions - - dotest log-o0 "${testcvs} admin -o 1.2.2.2:: file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -done" - dotest log-o1 "${testcvs} admin -o ::1.2.2.1 file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -done" - dotest log-o2 "${testcvs} admin -o 1.2.2.1:: file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v -deleting revision 1\.2\.2\.2 -done" - dotest log-o3 "${testcvs} log file1" \ -"${log_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 5 -description: -${log_rev4} -${log_rev3} -${log_rev2} -${log_rev1} -${log_rev1b} -${log_trailer}" - dotest log-ro3 "${testcvs} rlog first-dir/file1" \ -"${rlog_header1} -${log_tags1} -${log_keyword} -total revisions: 5; selected revisions: 5 -description: -${log_rev4} -${log_rev3} -${log_rev2} -${log_rev1} -${log_rev1b} -${log_trailer}" - dotest log-o4 "${testcvs} -q update -p -r 1.2.2.1 file1" \ -"first branch revision" - - cd .. - rm -r first-dir - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - log2) - # More "cvs log" tests, for example the file description. - - # Check in a file - mkdir ${CVSROOT_DIRNAME}/first-dir - dotest log2-1 "${testcvs} -q co first-dir" '' - cd first-dir - echo 'first revision' > file1 - dotest log2-2 "${testcvs} add -m file1-is-for-testing file1" \ -"${PROG}"' add: scheduling file `file1'\'' for addition -'"${PROG}"' add: use .'"${PROG}"' commit. to add this file permanently' - dotest log2-3 "${testcvs} -q commit -m 1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - # Setting the file description with add -m doesn't yet work - # client/server, so skip log2-4 for remote. - if $remote; then :; else - - dotest log2-4 "${testcvs} log -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: -file1-is-for-testing ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -1 -=============================================================================" - - fi # end of tests skipped for remote - - dotest log2-5 "${testcvs} admin -t-change-description file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done" - dotest log2-6 "${testcvs} log -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: -change-description ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -1 -=============================================================================" - - echo 'longer description' >${TESTDIR}/descrip - echo 'with two lines' >>${TESTDIR}/descrip - dotest log2-7 "${testcvs} admin -t${TESTDIR}/descrip file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done" - dotest_fail log2-7a "${testcvs} admin -t${TESTDIR}/nonexist file1" \ -"${PROG} \[[a-z]* aborted\]: can't stat ${TESTDIR}/nonexist: No such file or directory" - dotest log2-8 "${testcvs} log -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: -longer description -with two lines ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -1 -=============================================================================" - - # 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. - - dotest log2-9 "echo change from stdin | ${testcvs} admin -t -q file1" "" - dotest log2-10 "${testcvs} log -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: -change from stdin ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -1 -=============================================================================" - - cd .. - rm ${TESTDIR}/descrip - rm -r first-dir - rm -rf ${CVSROOT_DIRNAME}/first-dir - - ;; - - 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 ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - echo hi >file1 - dotest logopt-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest logopt-4 "${testcvs} -q ci -m add file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - cd .. - - dotest logopt-5 "${testcvs} log -R -d 2038-01-01" \ -"${PROG} log: Logging \. -${PROG} log: Logging first-dir -${CVSROOT_DIRNAME}/first-dir/file1,v" - dotest logopt-6 "${testcvs} log -d 2038-01-01 -R" \ -"${PROG} log: Logging \. -${PROG} log: Logging first-dir -${CVSROOT_DIRNAME}/first-dir/file1,v" - dotest logopt-6a "${testcvs} log -Rd 2038-01-01" \ -"${PROG} log: Logging \. -${PROG} log: Logging first-dir -${CVSROOT_DIRNAME}/first-dir/file1,v" - dotest logopt-7 "${testcvs} log -s Exp -R" \ -"${PROG} log: Logging \. -${PROG} log: Logging first-dir -${CVSROOT_DIRNAME}/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 - # rcs Annotate and the year 2000 - # keywordlog Annotate and $Log. - mkdir 1; cd 1 - dotest ann-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest ann-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - cat >file1 <<EOF -this -is -the -ancestral -file -EOF - dotest ann-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest ann-4 "${testcvs} -q ci -m add file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - cat >file1 <<EOF -this -is -a -file - -with -a -blank -line -EOF - dotest ann-5 "${testcvs} -q ci -m modify file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - dotest ann-6 "${testcvs} -q tag -b br" "T file1" - cat >file1 <<EOF -this -is -a -trunk file - -with -a -blank -line -EOF - dotest ann-7 "${testcvs} -q ci -m modify file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 -done" - dotest ann-8 "${testcvs} -q update -r br" "[UP] file1" - cat >file1 <<EOF -this -is -a -file - -with -a -blank -line -and some -branched content -EOF - dotest ann-9 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2\.2\.1; previous revision: 1\.2 -done" - # Note that this annotates the trunk despite the presence - # of a sticky tag in the current directory. This is - # fairly bogus, but it is the longstanding behavior for - # whatever that is worth. - dotest ann-10 "${testcvs} ann" \ -" -Annotations for file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1 ($username8 *[0-9a-zA-Z-]*): this -1\.1 ($username8 *[0-9a-zA-Z-]*): is -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.3 ($username8 *[0-9a-zA-Z-]*): trunk file -1\.2 ($username8 *[0-9a-zA-Z-]*): -1\.2 ($username8 *[0-9a-zA-Z-]*): with -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.2 ($username8 *[0-9a-zA-Z-]*): blank -1\.2 ($username8 *[0-9a-zA-Z-]*): line" - dotest ann-10blame "${testcvs} blame" \ -" -Annotations for file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1 ($username8 *[0-9a-zA-Z-]*): this -1\.1 ($username8 *[0-9a-zA-Z-]*): is -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.3 ($username8 *[0-9a-zA-Z-]*): trunk file -1\.2 ($username8 *[0-9a-zA-Z-]*): -1\.2 ($username8 *[0-9a-zA-Z-]*): with -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.2 ($username8 *[0-9a-zA-Z-]*): blank -1\.2 ($username8 *[0-9a-zA-Z-]*): line" - dotest ann-11 "${testcvs} ann -r br" \ -" -Annotations for file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1 ($username8 *[0-9a-zA-Z-]*): this -1\.1 ($username8 *[0-9a-zA-Z-]*): is -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.1 ($username8 *[0-9a-zA-Z-]*): file -1\.2 ($username8 *[0-9a-zA-Z-]*): -1\.2 ($username8 *[0-9a-zA-Z-]*): with -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.2 ($username8 *[0-9a-zA-Z-]*): blank -1\.2 ($username8 *[0-9a-zA-Z-]*): line -1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): and some -1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): branched content" - # FIXCVS: shouldn't "-r 1.2.0.2" be the same as "-r br"? - dotest ann-12 "${testcvs} ann -r 1.2.0.2 file1" "" - dotest ann-13 "${testcvs} ann -r 1.2.2 file1" \ -" -Annotations for file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1 ($username8 *[0-9a-zA-Z-]*): this -1\.1 ($username8 *[0-9a-zA-Z-]*): is -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.1 ($username8 *[0-9a-zA-Z-]*): file -1\.2 ($username8 *[0-9a-zA-Z-]*): -1\.2 ($username8 *[0-9a-zA-Z-]*): with -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.2 ($username8 *[0-9a-zA-Z-]*): blank -1\.2 ($username8 *[0-9a-zA-Z-]*): line -1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): and some -1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): branched content" - dotest_fail ann-14 "${testcvs} ann -r bill-clintons-chastity file1" \ -"${PROG} \[annotate aborted\]: no such tag bill-clintons-chastity" - - # Now get rid of the working directory and test rannotate - - cd ../.. - rm -r 1 - dotest ann-r10 "${testcvs} rann first-dir" \ -" -Annotations for first-dir/file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1 ($username8 *[0-9a-zA-Z-]*): this -1\.1 ($username8 *[0-9a-zA-Z-]*): is -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.3 ($username8 *[0-9a-zA-Z-]*): trunk file -1\.2 ($username8 *[0-9a-zA-Z-]*): -1\.2 ($username8 *[0-9a-zA-Z-]*): with -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.2 ($username8 *[0-9a-zA-Z-]*): blank -1\.2 ($username8 *[0-9a-zA-Z-]*): line" - dotest ann-r11 "${testcvs} rann -r br first-dir" \ -" -Annotations for first-dir/file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1 ($username8 *[0-9a-zA-Z-]*): this -1\.1 ($username8 *[0-9a-zA-Z-]*): is -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.1 ($username8 *[0-9a-zA-Z-]*): file -1\.2 ($username8 *[0-9a-zA-Z-]*): -1\.2 ($username8 *[0-9a-zA-Z-]*): with -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.2 ($username8 *[0-9a-zA-Z-]*): blank -1\.2 ($username8 *[0-9a-zA-Z-]*): line -1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): and some -1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): branched content" - dotest ann-r12 "${testcvs} rann -r 1.2.0.2 first-dir/file1" "" - dotest ann-r13 "${testcvs} rann -r 1.2.2 first-dir/file1" \ -" -Annotations for first-dir/file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1 ($username8 *[0-9a-zA-Z-]*): this -1\.1 ($username8 *[0-9a-zA-Z-]*): is -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.1 ($username8 *[0-9a-zA-Z-]*): file -1\.2 ($username8 *[0-9a-zA-Z-]*): -1\.2 ($username8 *[0-9a-zA-Z-]*): with -1\.2 ($username8 *[0-9a-zA-Z-]*): a -1\.2 ($username8 *[0-9a-zA-Z-]*): blank -1\.2 ($username8 *[0-9a-zA-Z-]*): line -1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): and some -1\.2\.2\.1 ($username8 *[0-9a-zA-Z-]*): branched content" - dotest_fail ann-r14 "${testcvs} rann -r bill-clintons-chastity first-dir/file1" \ -"${PROG} \[rannotate aborted\]: no such tag bill-clintons-chastity" - - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - ann-id) - # Demonstrate that cvs-1.9.28.1 improperly expands rcs keywords in - # the output of `cvs annotate' -- it uses values from the previous - # delta. In this case, `1.1' instead of `1.2', even though it puts - # the proper version number on the prefix to each line of output. - mkdir 1; cd 1 - dotest ann-id-1 "${testcvs} -q co -l ." '' - module=x - mkdir $module - dotest ann-id-2 "${testcvs} add $module" \ -"Directory ${CVSROOT_DIRNAME}/$module added to the repository" - cd $module - - file=m - echo '$Id''$' > $file - - dotest ann-id-3 "$testcvs add $file" \ -"${PROG} add: scheduling file .$file. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest ann-id-4 "$testcvs -Q ci -m . $file" \ -"RCS file: ${CVSROOT_DIRNAME}/$module/$file,v -done -Checking in $file; -${CVSROOT_DIRNAME}/$module/$file,v <-- $file -initial revision: 1\.1 -done" - - echo line2 >> $file - dotest ann-id-5 "$testcvs -Q ci -m . $file" \ -"Checking in $file; -${CVSROOT_DIRNAME}/$module/$file,v <-- $file -new revision: 1\.2; previous revision: 1\.1 -done" - - # The version number after $file,v should be `1.2'. - # 1.9.28.1 puts `1.1' there. - dotest ann-id-6 "$testcvs -Q ann $file" \ -" -Annotations for $file -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1.2 ($username8 *[0-9a-zA-Z-]*): "'\$'"Id: $file,v 1.1 [0-9/]* [0-9:]* $username Exp "'\$'" -1.2 ($username8 *[0-9a-zA-Z-]*): line2" - - cd ../.. - rm -rf 1 - rm -rf ${CVSROOT_DIRNAME}/$module - ;; - - crerepos) - # Various tests relating to creating repositories, operating - # on repositories created with old versions of CVS, etc. - - CVS_SERVER_save=$CVS_SERVER - - # Because this test is all about -d options and such, it - # at least to some extent needs to be different for remote vs. - # local. - if $remote; then - - # Use :ext: rather than :fork:. Most of the tests use :fork:, - # so we want to make sure that we test :ext: _somewhere_. - # Make sure 'rsh' works first. - depends_on_rsh "$CVS_RSH" - if test $? -eq 77; then - skip crerepos "$skipreason" - continue - fi - - # For remote, just create the repository. We don't yet do - # the various other tests above for remote but that should be - # changed. - mkdir crerepos - mkdir crerepos/CVSROOT - - # Make sure server ignores real ${HOME}/.cvsrc: - cat >$TESTDIR/cvs-setHome <<EOF -#!/bin/sh -HOME=$HOME -export HOME -exec $CVS_SERVER_save "\$@" -EOF - chmod a+x $TESTDIR/cvs-setHome - - # Note that we set CVS_SERVER at the beginning. - CVS_SERVER=$TESTDIR/cvs-setHome; export CVS_SERVER - CREREPOS_ROOT=:ext:$host$TESTDIR/crerepos - else - - # First, if the repository doesn't exist at all... - dotest_fail crerepos-1 \ -"${testcvs} -d ${TESTDIR}/crerepos co cvs-sanity" \ -"${PROG} \[checkout aborted\]: ${TESTDIR}/crerepos/CVSROOT: .*" - mkdir crerepos - - # The repository exists but CVSROOT doesn't. - dotest_fail crerepos-2 \ -"${testcvs} -d ${TESTDIR}/crerepos co cvs-sanity" \ -"${PROG} \[checkout aborted\]: ${TESTDIR}/crerepos/CVSROOT: .*" - mkdir crerepos/CVSROOT - - # Checkout of nonexistent module - dotest_fail crerepos-3 \ -"${testcvs} -d ${TESTDIR}/crerepos co cvs-sanity" \ -"${PROG} checkout: cannot find module .cvs-sanity. - ignored" - - # Now test that CVS works correctly without a modules file - # or any of that other stuff. In particular, it *must* - # function if administrative files added to CVS recently (since - # CVS 1.3) do not exist, because the repository might have - # been created with an old version of CVS. - mkdir 1; cd 1 - dotest crerepos-4 \ -"${testcvs} -q -d ${TESTDIR}/crerepos co CVSROOT" \ -'' - if echo yes | \ -${testcvs} -d ${TESTDIR}/crerepos release -d CVSROOT >>${LOGFILE}; then - pass crerepos-5 - else - fail crerepos-5 - fi - rm -rf CVS - cd .. - # The directory 1 should be empty - dotest crerepos-6 "rmdir 1" - - CREREPOS_ROOT=${TESTDIR}/crerepos - - fi - - if $remote; then - # Test that CVS rejects a relative path in CVSROOT. - mkdir 1; cd 1 - # Note that having the client reject the pathname (as :fork: - # does), does _not_ test for the bugs we are trying to catch - # here. The point is that malicious clients might send all - # manner of things and the server better protect itself. - dotest_fail crerepos-6a-r \ -"${testcvs} -q -d :ext:`hostname`:../crerepos get ." \ -"${PROG} [a-z]*: CVSROOT may only specify a positive, non-zero, integer port (not .\.\..)\. -${PROG} [a-z]*: Perhaps you entered a relative pathname${QUESTION} -${PROG} \[[a-z]* aborted\]: Bad CVSROOT: .:ext:${hostname}:\.\./crerepos.\." - cd .. - rm -r 1 - else # local - # Test that CVS rejects a relative path in CVSROOT. - - mkdir 1; cd 1 - # Set CVS_RSH=false since ocassionally (e.g. when CVS_RSH=ssh on - # some systems) some rsh implementations will block because they - # can look up '..' and want to ask the user about the unknown host - # key or somesuch. Which error message we get depends on whether - # false finishes running before we try to talk to it or not. - dotest_fail crerepos-6a "CVS_RSH=false ${testcvs} -q -d ../crerepos get ." \ -"${PROG} \[checkout aborted\]: .*" \ -"${PROG} checkout: CVSROOT is set for a remote access method but your -${PROG} checkout: CVS executable doesn't support it\. -${PROG} \[checkout aborted\]: Bad CVSROOT: .\.\./crerepos.\." - cd .. - rm -r 1 - - mkdir 1; cd 1 - dotest_fail crerepos-6b "${testcvs} -d crerepos init" \ -"${PROG} init: CVSROOT must be an absolute pathname (not .crerepos.) -${PROG} init: when using local access method\. -${PROG} \[init aborted\]: Bad CVSROOT: .crerepos.\." - cd .. - rm -r 1 - fi # end of tests to be skipped for remote - - # CVS better not create a history file--if the administrator - # doesn't need it and wants to save on disk space, they just - # delete it. - dotest_fail crerepos-7 \ -"test -f ${TESTDIR}/crerepos/CVSROOT/history" '' - - # Now test mixing repositories. This kind of thing tends to - # happen accidentally when people work with several repositories. - mkdir 1; cd 1 - dotest crerepos-8 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest crerepos-9 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch file1 - dotest crerepos-10 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest crerepos-11 "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - cd ../.. - rm -r 1 - - mkdir 1; cd 1 - dotest crerepos-12 "${testcvs} -d ${CREREPOS_ROOT} -q co -l ." '' - mkdir crerepos-dir - dotest crerepos-13 "${testcvs} add crerepos-dir" \ -"Directory ${TESTDIR}/crerepos/crerepos-dir added to the repository" - cd crerepos-dir - touch cfile - dotest crerepos-14 "${testcvs} add cfile" \ -"${PROG} add: scheduling file .cfile. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest crerepos-15 "${testcvs} -q ci -m add-it" \ -"RCS file: ${TESTDIR}/crerepos/crerepos-dir/cfile,v -done -Checking in cfile; -${TESTDIR}/crerepos/crerepos-dir/cfile,v <-- cfile -initial revision: 1\.1 -done" - cd ../.. - rm -r 1 - - mkdir 1; cd 1 - dotest crerepos-16 "${testcvs} co first-dir" \ -"${PROG} checkout: Updating first-dir -U first-dir/file1" - dotest crerepos-17 "${testcvs} -d ${CREREPOS_ROOT} co crerepos-dir" \ -"${PROG} checkout: Updating crerepos-dir -U crerepos-dir/cfile" - dotest crerepos-18 "${testcvs} update" \ -"${PROG} update: Updating first-dir -${PROG} update: Updating crerepos-dir" - - cd .. - - CVS_SERVER=$CVS_SERVER_save; export CVS_SERVER - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -f $TESTDIR/cvs-setHome - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir ${TESTDIR}/crerepos - ;; - - - - crerepos-extssh) - # Various tests relating to creating repositories, operating - # on repositories created with old versions of CVS, etc. - - CVS_SERVER_save=$CVS_SERVER - - # Because this test is all about -d options and such, it - # at least to some extent needs to be different for remote vs. - # local. - if $remote; then - - # Use :extssh: rather than :fork:. Most of the tests use :fork:, - # so we want to make sure that we test :extssh: _somewhere_. - # Make sure 'ssh' works first. - depends_on_rsh "$CVS_RSH" - if test $? -eq 77; then - skip crerepos "$skipreason" - continue - fi - - # For remote, just create the repository. We don't yet do - # the various other tests above for remote but that should be - # changed. - mkdir crerepos - mkdir crerepos/CVSROOT - - # Make sure server ignores real ${HOME}/.cvsrc: - cat >$TESTDIR/cvs-setHome <<EOF -#!/bin/sh -HOME=$HOME -export HOME -exec $CVS_SERVER_save "\$@" -EOF - chmod a+x $TESTDIR/cvs-setHome - - # Note that we set CVS_SERVER at the beginning. - CVS_SERVER=$TESTDIR/cvs-setHome; export CVS_SERVER - CREREPOS_ROOT=:extssh:$host$TESTDIR/crerepos - else - - # First, if the repository doesn't exist at all... - dotest_fail crerepos-extssh-1 \ -"${testcvs} -d ${TESTDIR}/crerepos co cvs-sanity" \ -"${PROG} \[checkout aborted\]: ${TESTDIR}/crerepos/CVSROOT: .*" - mkdir crerepos - - # The repository exists but CVSROOT doesn't. - dotest_fail crerepos-extssh-2 \ -"${testcvs} -d ${TESTDIR}/crerepos co cvs-sanity" \ -"${PROG} \[checkout aborted\]: ${TESTDIR}/crerepos/CVSROOT: .*" - mkdir crerepos/CVSROOT - - # Checkout of nonexistent module - dotest_fail crerepos-extssh-3 \ -"${testcvs} -d ${TESTDIR}/crerepos co cvs-sanity" \ -"${PROG} checkout: cannot find module .cvs-sanity. - ignored" - - # Now test that CVS works correctly without a modules file - # or any of that other stuff. In particular, it *must* - # function if administrative files added to CVS recently (since - # CVS 1.3) do not exist, because the repository might have - # been created with an old version of CVS. - mkdir 1; cd 1 - dotest crerepos-extssh-4 \ -"${testcvs} -q -d ${TESTDIR}/crerepos co CVSROOT" \ -'' - if echo yes | \ -${testcvs} -d ${TESTDIR}/crerepos release -d CVSROOT >>${LOGFILE}; then - pass crerepos-extssh-5 - else - fail crerepos-extssh-5 - fi - rm -rf CVS - cd .. - # The directory 1 should be empty - dotest crerepos-extssh-6 "rmdir 1" - - CREREPOS_ROOT=${TESTDIR}/crerepos - - fi - - if $remote; then - # Test that CVS rejects a relative path in CVSROOT. - mkdir 1; cd 1 - # Note that having the client reject the pathname (as :fork: - # does), does _not_ test for the bugs we are trying to catch - # here. The point is that malicious clients might send all - # manner of things and the server better protect itself. - dotest_fail crerepos-extssh-6a-r \ -"${testcvs} -q -d :extssh:`hostname`:../crerepos get ." \ -"${PROG} [a-z]*: CVSROOT may only specify a positive, non-zero, integer port (not .\.\..)\. -${PROG} [a-z]*: Perhaps you entered a relative pathname${QUESTION} -${PROG} \[[a-z]* aborted\]: Bad CVSROOT: .:extssh:${hostname}:\.\./crerepos.\." - cd .. - rm -r 1 - else # local - # Test that CVS rejects a relative path in CVSROOT. - - mkdir 1; cd 1 - # Set CVS_RSH=false since ocassionally (e.g. when CVS_RSH=ssh on - # some systems) some rsh implementations will block because they - # can look up '..' and want to ask the user about the unknown host - # key or somesuch. Which error message we get depends on whether - # false finishes running before we try to talk to it or not. - dotest_fail crerepos-extssh-6a "CVS_RSH=false ${testcvs} -q -d ../crerepos get ." \ -"${PROG} \[checkout aborted\]: .*" \ -"${PROG} checkout: CVSROOT is set for a remote access method but your -${PROG} checkout: CVS executable doesn't support it\. -${PROG} \[checkout aborted\]: Bad CVSROOT: .\.\./crerepos.\." - cd .. - rm -r 1 - - mkdir 1; cd 1 - dotest_fail crerepos-extssh-6b "${testcvs} -d crerepos init" \ -"${PROG} init: CVSROOT must be an absolute pathname (not .crerepos.) -${PROG} init: when using local access method\. -${PROG} \[init aborted\]: Bad CVSROOT: .crerepos.\." - cd .. - rm -r 1 - fi # end of tests to be skipped for remote - - # CVS better not create a history file--if the administrator - # doesn't need it and wants to save on disk space, they just - # delete it. - dotest_fail crerepos-extssh-7 \ -"test -f ${TESTDIR}/crerepos/CVSROOT/history" '' - - # Now test mixing repositories. This kind of thing tends to - # happen accidentally when people work with several repositories. - mkdir 1; cd 1 - dotest crerepos-extssh-8 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest crerepos-extssh-9 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch file1 - dotest crerepos-extssh-10 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest crerepos-extssh-11 "${testcvs} -q ci -m add-it" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - cd ../.. - rm -r 1 - - mkdir 1; cd 1 - dotest crerepos-extssh-12 "${testcvs} -d ${CREREPOS_ROOT} -q co -l ." '' - mkdir crerepos-dir - dotest crerepos-extssh-13 "${testcvs} add crerepos-dir" \ -"Directory ${TESTDIR}/crerepos/crerepos-dir added to the repository" - cd crerepos-dir - touch cfile - dotest crerepos-extssh-14 "${testcvs} add cfile" \ -"${PROG} add: scheduling file .cfile. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest crerepos-extssh-15 "${testcvs} -q ci -m add-it" \ -"RCS file: ${TESTDIR}/crerepos/crerepos-dir/cfile,v -done -Checking in cfile; -${TESTDIR}/crerepos/crerepos-dir/cfile,v <-- cfile -initial revision: 1\.1 -done" - cd ../.. - rm -r 1 - - mkdir 1; cd 1 - dotest crerepos-extssh-16 "${testcvs} co first-dir" \ -"${PROG} checkout: Updating first-dir -U first-dir/file1" - dotest crerepos-extssh-17 "${testcvs} -d ${CREREPOS_ROOT} co crerepos-dir" \ -"${PROG} checkout: Updating crerepos-dir -U crerepos-dir/cfile" - dotest crerepos-extssh-18 "${testcvs} update" \ -"${PROG} update: Updating first-dir -${PROG} update: Updating crerepos-dir" - - cd .. - - CVS_SERVER=$CVS_SERVER_save; export CVS_SERVER - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -f $TESTDIR/cvs-setHome - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir ${TESTDIR}/crerepos - ;; - - - - rcs) - # Test ability to import an RCS file. Note that this format - # is fixed--files written by RCS5, and other software which - # implements this format, will be out there "forever" and - # CVS must always be able to import such files. - - # See tests admin-13, admin-25 and rcs-8a for exporting RCS files. - - mkdir ${CVSROOT_DIRNAME}/first-dir - - # Currently the way to import an RCS file is to copy it - # directly into the repository. - # - # This file was written by RCS 5.7, and then the dates were - # hacked so that we test year 2000 stuff. Note also that - # "author" names are just strings, as far as importing - # RCS files is concerned--they need not correspond to user - # IDs on any particular system. - # - # I also tried writing a file with the RCS supplied with - # HPUX A.09.05. According to "man rcsintro" this is - # "Revision Number: 3.0; Release Date: 83/05/11". There - # were a few minor differences like whitespace but at least - # in simple cases like this everything else seemed the same - # as the file written by RCS 5.7 (so I won't try to make it - # a separate test case). - - cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v -head 1.3; -access; -symbols; -locks; strict; -comment @# @; - - -1.3 -date 2000.11.24.15.58.37; author kingdon; state Exp; -branches; -next 1.2; - -1.2 -date 96.11.24.15.57.41; author kingdon; state Exp; -branches; -next 1.1; - -1.1 -date 96.11.24.15.56.05; author kingdon; state Exp; -branches; -next ; - - -desc -@file1 is for testing CVS -@ - - -1.3 -log -@delete second line; modify twelfth line -@ -text -@This is the first line -This is the third line -This is the fourth line -This is the fifth line -This is the sixth line -This is the seventh line -This is the eighth line -This is the ninth line -This is the tenth line -This is the eleventh line -This is the twelfth line (and what a line it is) -This is the thirteenth line -@ - - -1.2 -log -@add more lines -@ -text -@a1 1 -This is the second line -d11 1 -a11 1 -This is the twelfth line -@ - - -1.1 -log -@add file1 -@ -text -@d2 12 -@ -EOF - dotest rcs-1 "${testcvs} -q co first-dir" 'U first-dir/file1' - cd first-dir - dotest rcs-2 "${testcvs} -q log" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.3 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 3; selected revisions: 3 -description: -file1 is for testing CVS ----------------------------- -revision 1\.3 -date: 2000/11/24 15:58:37; author: kingdon; state: Exp; lines: ${PLUS}1 -2 -delete second line; modify twelfth line ----------------------------- -revision 1\.2 -date: 1996/11/24 15:57:41; author: kingdon; state: Exp; lines: ${PLUS}12 -0 -add more lines ----------------------------- -revision 1\.1 -date: 1996/11/24 15:56:05; author: kingdon; state: Exp; -add file1 -=============================================================================" - - # Note that the dates here are chosen so that (a) we test - # at least one date after 2000, (b) we will notice if the - # month and day are getting mixed up with each other. - # TODO: also test that year isn't getting mixed up with month - # or day, for example 01-02-03. - - # 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<'" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.3 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 3; selected revisions: 1 -description: -file1 is for testing CVS ----------------------------- -revision 1\.3 -date: 2000/11/24 15:58:37; author: kingdon; state: Exp; lines: ${PLUS}1 -2 -delete second line; modify twelfth line -=============================================================================" - - # RFC822 format (as amended by RFC1123). - dotest rcs-4 "${testcvs} -q log -d '<3 Apr 2000 00:00'" \ -" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.3 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 3; selected revisions: 2 -description: -file1 is for testing CVS ----------------------------- -revision 1\.2 -date: 1996/11/24 15:57:41; author: kingdon; state: Exp; lines: ${PLUS}12 -0 -add more lines ----------------------------- -revision 1\.1 -date: 1996/11/24 15:56:05; author: kingdon; state: Exp; -add file1 -=============================================================================" - - # Intended behavior for "cvs annotate" is that it displays the - # last two digits of the year. Make sure it does that rather - # than some bogosity like "100". - dotest rcs-4a "${testcvs} annotate file1" \ -" -Annotations for file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1 (kingdon 24-Nov-96): This is the first line -1\.2 (kingdon 24-Nov-96): This is the third line -1\.2 (kingdon 24-Nov-96): This is the fourth line -1\.2 (kingdon 24-Nov-96): This is the fifth line -1\.2 (kingdon 24-Nov-96): This is the sixth line -1\.2 (kingdon 24-Nov-96): This is the seventh line -1\.2 (kingdon 24-Nov-96): This is the eighth line -1\.2 (kingdon 24-Nov-96): This is the ninth line -1\.2 (kingdon 24-Nov-96): This is the tenth line -1\.2 (kingdon 24-Nov-96): This is the eleventh line -1\.3 (kingdon 24-Nov-00): This is the twelfth line (and what a line it is) -1\.2 (kingdon 24-Nov-96): This is the thirteenth line" - - # Probably should split this test into two at this point (file1 - # above this line and file2 below), as the two share little - # data/setup. - - # OK, here is another one. This one was written by hand based on - # doc/RCSFILES and friends. One subtle point is that none of - # the lines end with newlines; that is a feature which we - # should be testing. - cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file2,v -head 1.5 ; - branch 1.2.6; -access ; -symbols branch:1.2.6; -locks; -testofanewphrase @without newphrase we'd have trouble extending @@ all@ ; -1.5 date 71.01.01.01.00.00; author joe; state bogus; branches; next 1.4; -1.4 date 71.01.01.00.00.05; author joe; state bogus; branches; next 1.3; -1.3 date 70.12.31.15.00.05; author joe; state bogus; branches; next 1.2; -1.2 date 70.12.31.12.15.05; author me; state bogus; branches 1.2.6.1; next 1.1; -1.1 date 70.12.31.11.00.05; author joe; state bogus; branches; next; newph; -1.2.6.1 date 71.01.01.08.00.05; author joe; state Exp; branches; next; -desc @@ -1.5 log @@ newphrase1; newphrase2 42; text @head revision@ -1.4 log @@ text @d1 1 -a1 1 -new year revision@ -1.3 log @@ text @d1 1 -a1 1 -old year revision@ -1.2 log @@ text @d1 1 -a1 1 -mid revision@ 1.1 - -log @@ text @d1 1 -a1 1 -start revision@ -1.2.6.1 log @@ text @d1 1 -a1 1 -branch revision@ -EOF - # ' Match the single quote in above here doc -- for font-lock mode. - - # First test the default branch. - dotest rcs-5 "${testcvs} -q update file2" "U file2" - dotest rcs-6 "cat file2" "branch revision" - - # Check in a revision on the branch to force CVS to - # interpret every revision in the file. - dotest rcs-6a "$testcvs -q update -r branch file2" 'U file2' - echo "next branch revision" > file2 - dotest rcs-6b "${testcvs} -q ci -m mod file2" \ -"Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.2\.6\.2; previous revision: 1\.2\.6\.1 -done" - - # Now get rid of the default branch, it will get in the way. - dotest rcs-7 "${testcvs} admin -b file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - # But we do want to make sure that "cvs admin" leaves the newphrases - # in the file. - # The extra whitespace regexps are for the RCS library, which does - # not preserve whitespace in the dogmatic manner of RCS 5.7. -twp - dotest rcs-8 \ -"grep testofanewphrase ${CVSROOT_DIRNAME}/first-dir/file2,v" \ -"testofanewphrase[ ][ ]*@without newphrase we'd have trouble extending @@ all@[ ]*;" - # The easiest way to test for newphrases in deltas and deltatexts - # is to just look at the whole file, I guess. - dotest rcs-8a "cat ${CVSROOT_DIRNAME}/first-dir/file2,v" \ -"head 1\.5; -access; -symbols - branch:1.2.6; -locks; - -testofanewphrase @without newphrase we'd have trouble extending @@ all@; - -1\.5 -date 71\.01\.01\.01\.00\.00; author joe; state bogus; -branches; -next 1\.4; - -1\.4 -date 71\.01\.01\.00\.00\.05; author joe; state bogus; -branches; -next 1\.3; - -1\.3 -date 70\.12\.31\.15\.00\.05; author joe; state bogus; -branches; -next 1\.2; - -1\.2 -date 70\.12\.31\.12\.15\.05; author me; state bogus; -branches - 1\.2\.6\.1; -next 1\.1; - -1\.1 -date 70\.12\.31\.11\.00\.05; author joe; state bogus; -branches; -next ; -newph ; - -1\.2\.6\.1 -date 71\.01\.01\.08\.00\.05; author joe; state Exp; -branches; -next 1\.2\.6\.2; - -1\.2\.6\.2 -date [0-9.]*; author ${username}; state Exp; -branches; -next ; - - -desc -@@ - - -1\.5 -log -@@ -newphrase1 ; -newphrase2 42; -text -@head revision@ - - -1\.4 -log -@@ -text -@d1 1 -a1 1 -new year revision@ - - -1\.3 -log -@@ -text -@d1 1 -a1 1 -old year revision@ - - -1\.2 -log -@@ -text -@d1 1 -a1 1 -mid revision@ - - -1\.1 -log -@@ -text -@d1 1 -a1 1 -start revision@ - - -1\.2\.6\.1 -log -@@ -text -@d1 1 -a1 1 -branch revision@ - - -1\.2\.6\.2 -log -@mod -@ -text -@d1 1 -a1 1 -next branch revision -@" - - dotest rcs-9 "${testcvs} -q update -p -D '1970-12-31 11:30 UT' file2" \ -"start revision" - - dotest rcs-10 "${testcvs} -q update -p -D '1970-12-31 12:30 UT' file2" \ -"mid revision" - - 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. - 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. - 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. - dotest rcs-14 "${testcvs} -q log file2" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -Working file: file2 -head: 1\.5 -branch: -locks: -access list: -symbolic names: - branch: 1\.2\.6 -keyword substitution: kv -total revisions: 7; selected revisions: 7 -description: ----------------------------- -revision 1\.5 -date: 1971/01/01 01:00:00; author: joe; state: bogus; lines: ${PLUS}1 -1 -\*\*\* empty log message \*\*\* ----------------------------- -revision 1\.4 -date: 1971/01/01 00:00:05; author: joe; state: bogus; lines: ${PLUS}1 -1 -\*\*\* empty log message \*\*\* ----------------------------- -revision 1\.3 -date: 1970/12/31 15:00:05; author: joe; state: bogus; lines: ${PLUS}1 -1 -\*\*\* empty log message \*\*\* ----------------------------- -revision 1\.2 -date: 1970/12/31 12:15:05; author: me; state: bogus; lines: ${PLUS}1 -1 -branches: 1\.2\.6; -\*\*\* empty log message \*\*\* ----------------------------- -revision 1\.1 -date: 1970/12/31 11:00:05; author: joe; state: bogus; -\*\*\* empty log message \*\*\* ----------------------------- -revision 1\.2\.6\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -1 -mod ----------------------------- -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 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - rcs2) - # More date tests. Might as well do this as a separate - # test from "rcs", so that we don't need to perturb the - # "written by RCS 5.7" RCS file. - mkdir ${CVSROOT_DIRNAME}/first-dir - # Significance of various dates: - # * At least one Y2K standard refers to recognizing 9 Sep 1999 - # (as an example of a pre-2000 date, I guess). - # * At least one Y2K standard refers to recognizing 1 Jan 2001 - # (as an example of a post-2000 date, I guess). - # * Many Y2K standards refer to 2000 being a leap year. - cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v -head 1.7; access; symbols; locks; strict; -1.7 date 2004.08.31.01.01.01; author sue; state; branches; next 1.6; -1.6 date 2004.02.29.01.01.01; author sue; state; branches; next 1.5; -1.5 date 2003.02.28.01.01.01; author sue; state; branches; next 1.4; -1.4 date 2001.01.01.01.01.01; author sue; state; branches; next 1.3; -1.3 date 2000.02.29.01.01.01; author sue; state; branches; next 1.2; -1.2 date 99.09.09.01.01.01; author sue; state; branches; next 1.1; -1.1 date 98.09.10.01.01.01; author sue; state; branches; next; -desc @a test file@ -1.7 log @@ text @head revision@ -1.6 log @@ text @d1 1 -a1 1 -2004 was a great year for leaping@ -1.5 log @@ text @d1 1 -a1 1 -2003 wasn't@ -1.4 log @@ text @d1 1 -a1 1 -two year hiatus@ -1.3 log @@ text @d1 1 -a1 1 -2000 is also a good year for leaping@ -1.2 log @@ text @d1 1 -a1 1 -Tonight we're going to party like it's a certain year@ -1.1 log @@ text @d1 1 -a1 1 -Need to start somewhere@ -EOF - # ' Match the 3rd single quote in the here doc -- for font-lock mode. - - dotest rcs2-1 "${testcvs} -q co first-dir" 'U first-dir/file1' - cd first-dir - - # 9 Sep 1999 - 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" - # 1 Jan 2001. - dotest rcs2-3 "${testcvs} -q update -p -D '2001-01-01 11:30 UT' file1" \ -"two year hiatus" - # 29 Feb 2000 - dotest rcs2-4 "${testcvs} -q update -p -D '2000-02-29 11:30 UT' file1" \ -"2000 is also a good year for leaping" - # 29 Feb 2003 is invalid - 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" - - dotest rcs2-6 "${testcvs} -q update -p -D 2007-01-07 file1" \ -"head revision" - # This assumes that the clock of the machine running the tests - # is set to at least the year 1998 or so. There don't seem - # to be a lot of ways to test the relative date code (short - # of something like LD_LIBRARY_PRELOAD'ing in our own - # getttimeofday, or hacking the CVS source with testing - # features, which always seems to be problematic since then - # someone feels like documenting them and things go downhill - # from there). - # - # These tests can be expected to fail 3 times every 400 years - # starting Feb. 29, 2096 (because 8 years from that date would - # be Feb. 29, 2100, which is an invalid date -- 2100 isn't a - # leap year because it's divisible by 100 but not by 400). - - dotest rcs2-7 "${testcvs} -q update -p -D '96 months' file1" \ -"head revision" - dotest rcs2-8 "${testcvs} -q update -p -D '8 years' file1" \ -"head revision" - - cd .. - rm -r first-dir - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - rcs3) - # More RCS file tests, in particular at least some of the - # error handling issues. - mkdir ${CVSROOT_DIRNAME}/first-dir - cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v -head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02 -; author jeremiah ;state ; branches; next;desc@@1.1log@@text@head@ -EOF - mkdir 1; cd 1 - # CVS requires whitespace between "desc" and its value. - # The rcsfile(5) manpage doesn't really seem to answer the - # question one way or the other (it has a grammar but almost - # nothing about lexical analysis). - dotest_fail rcs3-1 "${testcvs} -q co first-dir" \ -"${PROG} \[checkout aborted\]: EOF while looking for value in RCS file ${CVSROOT_DIRNAME}/first-dir/file1,v" - cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v -head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02 -; author jeremiah ;state ; branches; next;desc @@1.1log@@text@head@ -EOF - # Whitespace issues, likewise. - dotest_fail rcs3-2 "${testcvs} -q co first-dir" \ -"${PROG} \[checkout aborted\]: unexpected '.x6c' reading revision number in RCS file ${CVSROOT_DIRNAME}/first-dir/file1,v" - cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v -head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02 -; author jeremiah ;state ; branches; next;desc @@1.1 log@@text@head@ -EOF - # Charming array of different messages for similar - # whitespace issues (depending on where the whitespace is). - dotest_fail rcs3-3 "${testcvs} -q co first-dir" \ -"${PROG} \[checkout aborted\]: EOF while looking for value in RCS file ${CVSROOT_DIRNAME}/first-dir/file1,v" - cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v -head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02 -; author jeremiah ;state ; branches; next;desc @@1.1 log @@text @head@ -EOF - dotest rcs3-4 "${testcvs} -q co first-dir" 'U first-dir/file1' - - # 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 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 - dotest rcs3-6 "${testcvs} log -R file1" \ -"${CVSROOT_DIRNAME}/first-dir/file1,v" - - # OK, now put an extraneous '\0' at the end. - ${AWK} </dev/null 'BEGIN { printf "@%c", 10 }' | ${TR} '@' '\000' \ - >>${CVSROOT_DIRNAME}/first-dir/file1,v - dotest_fail rcs3-7 "${testcvs} log -s nostate file1" \ -"${PROG} \[log aborted\]: unexpected '.x0' reading revision number in RCS file ${CVSROOT_DIRNAME}/first-dir/file1,v" - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - rcs4) - # Fix a bug that shows up when checking out files by date with the - # "-D date" command line option. There is code in the original to - # handle a special case. If the date search finds revision 1.1 it - # is supposed to check whether revision 1.1.1.1 has the same date - # stamp, which would indicate that the file was originally brought - # in with "cvs import". In that case it is supposed to return the - # vendor branch version 1.1.1.1. - # - # However, there is a bug in the code. It actually compares - # the date of revision 1.1 for equality with the date given - # on the command line -- clearly wrong. This commit fixes - # the coding bug. - # - # There is an additional bug which is _not_ fixed yet. - # The date comparison should not be a strict - # equality test. It should allow a fudge factor of, say, 2-3 - # seconds. Old versions of CVS created the two revisions - # with two separate invocations of the RCS "ci" command. We - # have many old files in the tree in which the dates of - # revisions 1.1 and 1.1.1.1 differ by 1 second. - - mkdir rcs4 - cd rcs4 - - mkdir imp-dir - cd imp-dir - echo 'OpenMunger sources' >file1 - - # choose a time in the past to demonstrate the problem - TZ=GMT touch -t 200012010123 file1 - - dotest_sort rcs4-1 \ -"${testcvs} import -d -m add rcs4-dir openmunger openmunger-1_0" \ -' - -N rcs4-dir/file1 -No conflicts created by this import' - echo 'OpenMunger sources release 1.1 extras' >>file1 - TZ=GMT touch -t 200112011234 file1 - dotest_sort rcs4-2 \ -"${testcvs} import -d -m add rcs4-dir openmunger openmunger-1_1" \ -' - -No conflicts created by this import -U rcs4-dir/file1' - cd .. - # Next checkout the new module - dotest rcs4-3 \ -"${testcvs} -q co rcs4-dir" \ -'U rcs4-dir/file1' - cd rcs4-dir - echo 'local change' >> file1 - - # commit a local change - dotest rcs4-4 \ -"${testcvs} -q commit -m hack file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/rcs4-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - # now see if we get version 1.1 or 1.1.1.1 when we ask for - # a checkout by time... it really should be 1.1.1.1 as - # that was indeed the version that was visible at the target - # time. - dotest rcs4-5 \ -"${testcvs} -q update -D 'October 1, 2001 UTC' file1" \ -'[UP] file1' - dotest rcs4-6 \ -"${testcvs} -q status file1" \ -'=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1\.1\.1.* - Repository revision: 1\.1\.1\.1 '${CVSROOT_DIRNAME}'/rcs4-dir/file1,v - Sticky Tag: (none) - Sticky Date: 2001\.10\.01\.00\.00\.00 - Sticky Options: (none)' - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd ../.. - rm -r rcs4 - rm -rf ${CVSROOT_DIRNAME}/rcs4-dir - ;; - - - - rcs5) - # Some tests of the $Log keyword and log message without a trailing - # EOL. This used to look ugly and, in the worst case, could cause - # a seg fault due to a buffer overflow. - # - # Note that it should not be possible to create this situation via a - # CVS server (and any client), since the server itself inserts the - # trailing EOL onto log messages that are missing one. Still, we - # shouldn't segfault due to a corrupt RCS file and I think that a log - # message without the trailing EOL doesn't actually violate the RCS - # spec, though it doesn't appear to be possible to create such a log - # message using RCS 5.7. - - mkdir $CVSROOT_DIRNAME/rcs5 - cat <<\EOF >$CVSROOT_DIRNAME/rcs5/file1,v -head 1.1; -access; -symbols; -locks; -expand kv; - -1.1 date 2007.03.20.04.03.02; author jeremiah; state Ext; branches; next; - -desc -@@ - -1.1 -log -@he always had very fine wine@ -text -@line1 -/* -EOF -echo ' * Revision history: $''Log$' >>$CVSROOT_DIRNAME/rcs5/file1,v - cat <<\EOF >>$CVSROOT_DIRNAME/rcs5/file1,v - */ -line5 -@ -EOF - - mkdir rcs5 - cd rcs5 - dotest rcs5-1 "$testcvs -Q co rcs5" - dotest rcs5-2 "cat rcs5/file1" \ -"line1 -/\\* - \\* Revision history: "'\$'"Log: file1,v "'\$'" - \\* Revision history: Revision 1\.1 2007/03/20 04:03:02 jeremiah - \\* Revision history: he always had very fine wine - \\* Revision history: - \\*/ -line5" - - cd .. - rm -r rcs5 - rm -rf $CVSROOT_DIRNAME/rcs5 - ;; - - - - rcs6) - # Test that CVS notices a specific type of corruption in the RCS - # archive. In the past, this type of corruption had turned up after - # a user ineptly attempted to delete a revision from an arcvhive - # manually. - mkdir rcs6; cd rcs6 - - # Make the project. - dotest rcs6-init-1 "$testcvs -Q co -ld top .; cd top" - mkdir rcs6 - dotest rcs6-init-2 "$testcvs -Q add rcs6" - cd rcs6 - - # Populate it. - echo some words >afile - dotest rcs6-init-3 "$testcvs -Q add afile" - dotest rcs6-init-4 "$testcvs -Q ci -mnewfile afile" \ -"RCS file: $CVSROOT_DIRNAME/rcs6/afile,v -done -Checking in afile; -$CVSROOT_DIRNAME/rcs6/afile,v <-- afile -initial revision: 1\.1 -done" - echo more words >>afile - dotest rcs6-init-5 "$testcvs -Q ci -mrev2 afile" \ -"Checking in afile; -$CVSROOT_DIRNAME/rcs6/afile,v <-- afile -new revision: 1\.2; previous revision: 1\.1 -done" - - # Corrupt the archive. - sed -e '8,12d' \ - -e 's/^head 1\.2/head 1.1/' \ - <$CVSROOT_DIRNAME/rcs6/afile,v \ - >$CVSROOT_DIRNAME/rcs6/cfile,v - - # Update used to work. - dotest_fail rcs6-1 "$testcvs -q up" \ -"$PROG \[update aborted\]: Expected head revision 1\.1, found 1\.2\." - - # Then a commit hosed the archive further without any warnings. - # Updating to an old revision (e.g. 1.1) would have reported the - # corruption. A second commit would have deleted data from the - # file. - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd ../../.. - rm -r rcs6 - rm -rf $CVSROOT_DIRNAME/rcs6 - ;; - - - - lockfiles) - # Tests of CVS lock files. - # TODO-maybe: Add a test where we arrange for a loginfo - # script (or some such) to ensure that locks are in place - # so then we can see how they are behaving. - - mkdir 1; cd 1 - mkdir sdir - mkdir sdir/ssdir - echo file >sdir/ssdir/file1 - dotest lockfiles-1 \ -"${testcvs} -Q import -m import-it first-dir bar baz" "" - cd .. - - mkdir 2; cd 2 - dotest lockfiles-2 "${testcvs} -q co first-dir" \ -"U first-dir/sdir/ssdir/file1" - dotest lockfiles-3 "${testcvs} -Q co CVSROOT" "" - cd CVSROOT - echo "LockDir=${TESTDIR}/locks" >config - dotest lockfiles-4 "${testcvs} -q ci -m config-it" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../first-dir/sdir/ssdir - # The error message appears twice because Lock_Cleanup only - # stops recursing after the first attempt. - dotest_fail lockfiles-5 "${testcvs} -q update" \ -"${PROG} \[update aborted\]: cannot stat ${TESTDIR}/locks: No such file or directory -${PROG} \[update aborted\]: cannot stat ${TESTDIR}/locks: No such file or directory" - mkdir ${TESTDIR}/locks - # Grumble, mumble. Cygwin. - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod u=rwx,g=r,o= ${TESTDIR}/locks" - else - chmod u=rwx,g=r,o= ${TESTDIR}/locks - fi - umask 0077 - CVSUMASK=0077; export CVSUMASK - dotest lockfiles-6 "${testcvs} -q update" "" - # TODO: should also be testing that CVS continues to honor the - # umask and CVSUMASK normally. In the case of the umask, CVS - # doesn't seem to use it for much (although it perhaps should). - dotest lockfiles-7 "ls ${TESTDIR}/locks/first-dir/sdir/ssdir" "" - - # The policy is that when CVS creates new lock directories, they - # inherit the permissions from the parent directory. CVSUMASK - # isn't right, because typically the reason for LockDir is to - # use a different set of permissions. - # - # Bah! Cygwin! - if test -n "$remotehost"; then - dotest lockfiles-7a "$CVS_RSH $remotehost 'ls -ld ${TESTDIR}/locks/first-dir'" \ -"drwxr-----.*first-dir" - dotest lockfiles-7b "$CVS_RSH $remotehost 'ls -ld ${TESTDIR}/locks/first-dir/sdir/ssdir'" \ -"drwxr-----.*first-dir/sdir/ssdir" - else - dotest lockfiles-7a "ls -ld ${TESTDIR}/locks/first-dir" \ -"drwxr-----.*first-dir" - dotest lockfiles-7b "ls -ld ${TESTDIR}/locks/first-dir/sdir/ssdir" \ -"drwxr-----.*first-dir/sdir/ssdir" - fi - - cd ../../.. - dotest lockfiles-8 "${testcvs} -q update" "" - dotest lockfiles-9 "${testcvs} -q co -l ." "" - - ### - ### There are race conditions in the following tests, but hopefully - ### the 5 seconds the first process waits to remove the lockdir and - ### the 30 seconds CVS waits betweens checks will be significant - ### enough to render the case moot. - ### - # Considers the following cases: - # - # Lock Present - # Operation Allowed (case #) - # - # Read Write - # _______ ______ - # Read |Yes (1) No (3) - # Write |No (7) No (9) - # - # Tests do not appear in same ordering as table. The odd numbering - # scheme maintains correspondance with a larger table on 1.12.x: - # 1. Read when read locks are present... - # 3. Don't read when write locks present... - # 7. Don't write when read locks are present... - # 9. Don't write when write locks are present... - - # 3. Don't read when write locks present... - mkdir "$TESTDIR/locks/first-dir/#cvs.lock" - (sleep 5; rmdir "$TESTDIR/locks/first-dir/#cvs.lock")& - dotest lockfiles-10 "$testcvs -q co -l first-dir" \ -"$PROG checkout: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/first-dir -$PROG checkout: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/first-dir" - - # 1. Read when read locks are present... - touch "$TESTDIR/locks/first-dir/#cvs.rfl.test.lock" - dotest lockfiles-11 "$testcvs -q co -l first-dir" - rm "$TESTDIR/locks/first-dir/#cvs.rfl.test.lock" - - # 7. Don't write when read locks are present... - echo I always have trouble coming up with witty text for the test files >>first-dir/sdir/ssdir/file1 - touch "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.rfl.test.lock" - (sleep 5; rm "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.rfl.test.lock")& - dotest lockfiles-13 "$testcvs -q ci -mconflict first-dir" \ -"$PROG commit: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir -$PROG commit: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir -Checking in first-dir/sdir/ssdir/file1; -$CVSROOT_DIRNAME/first-dir/sdir/ssdir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - - # 9. Don't write when write locks are present... - echo yet this poem would probably only give longfellow bile >>first-dir/sdir/ssdir/file1 - mkdir "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.lock" - (sleep 5; rmdir "$TESTDIR/locks/first-dir/sdir/ssdir/#cvs.lock")& - dotest lockfiles-19 "$testcvs -q ci -mnot-up-to-date first-dir" \ -"$PROG commit: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir -$PROG commit: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/first-dir/sdir/ssdir -Checking in first-dir/sdir/ssdir/file1; -$CVSROOT_DIRNAME/first-dir/sdir/ssdir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 -done" - - # 10. Don't write when history locks are present... - echo have you ever heard a poem quite so vile\? >>first-dir/sdir/ssdir/file1 - mkdir "$TESTDIR/locks/CVSROOT/#cvs.history.lock" - (sleep 5; rmdir "$TESTDIR/locks/CVSROOT/#cvs.history.lock")& - dotest lockfiles-20 "$testcvs -q ci -mnot-up-to-date first-dir" \ -"Checking in first-dir/sdir/ssdir/file1; -$CVSROOT_DIRNAME/first-dir/sdir/ssdir/file1,v <-- file1 -new revision: 1\.4; previous revision: 1\.3 -done -$PROG commit: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/CVSROOT -$PROG commit: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/CVSROOT" - - dotest lockfiles-21 "$testcvs -Q tag newtag first-dir" - - rm -f $CVSROOT_DIRNAME/CVSROOT/val-tags - mkdir "$TESTDIR/locks/CVSROOT/#cvs.val-tags.lock" - (sleep 5; rmdir "$TESTDIR/locks/CVSROOT/#cvs.val-tags.lock")& - dotest lockfiles-22 "$testcvs -q up -r newtag first-dir" \ -"$PROG update: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/CVSROOT -$PROG update: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/CVSROOT -[UP] first-dir/sdir/ssdir/file1" - - cd CVSROOT - echo "# nobody here but us comments" >config - dotest lockfiles-cleanup-1 "${testcvs} -q ci -m config-it" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../.. - # Perhaps should restore the umask and CVSUMASK to what they - # were before. But the other tests "should" not care about them... - umask 0077 - unset CVSUMASK - rm -r ${TESTDIR}/locks - rm -r 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - backuprecover) - # Tests to make sure we get the expected behavior - # when we recover a repository from an old backup - # - # Details: - # Backup will be older than some developer's workspaces - # This means the first attempt at an update will fail - # The workaround for this is to replace the CVS - # directories with those from a "new" checkout from - # the recovered repository. Due to this, multiple - # merges should cause conflicts (the same data - # will be merged more than once). - # A workspace updated before the date of the recovered - # copy will not need any extra attention - # - # Note that backuprecover-15 is probably a failure case - # If nobody else had a more recent update, the data would be lost - # permanently - # Granted, the developer should have been notified not to do this - # by now, but still... - # - mkdir backuprecover; cd backuprecover - mkdir 1; cd 1 - dotest backuprecover-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest backuprecover-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - mkdir dir - dotest backuprecover-3 "${testcvs} add dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir added to the repository" - touch file1 dir/file2 - dotest backuprecover-4 "${testcvs} -q add file1 dir/file2" \ -"${PROG} add: use .${PROG} commit. to add these files permanently" - dotest backuprecover-5 "${testcvs} -q ci -mtest" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir/file2,v -done -Checking in dir/file2; -${CVSROOT_DIRNAME}/first-dir/dir/file2,v <-- file2 -initial revision: 1\.1 -done" - echo "Line one" >>file1 - echo " is the place" >>file1 - echo " we like to begin" >>file1 - echo "Anything else" >>file1 - echo " looks like" >>file1 - echo " a sin" >>file1 - echo "File 2" >>dir/file2 - echo " is the place" >>dir/file2 - echo " the rest of it goes" >>dir/file2 - echo "Why I don't use" >>dir/file2 - echo " something like 'foo'" >>dir/file2 - echo " God only knows" >>dir/file2 - dotest backuprecover-6 "${testcvs} -q ci -mtest" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done -Checking in dir/file2; -${CVSROOT_DIRNAME}/first-dir/dir/file2,v <-- file2 -new revision: 1\.2; previous revision: 1\.1 -done" - - # Simulate the lazy developer - # (he did some work but didn't check it in...) - cd ../.. - mkdir 2; cd 2 - dotest backuprecover-7 "${testcvs} -Q co first-dir" '' - cd first-dir - sed -e "s/looks like/just looks like/" file1 >tmp; mv tmp file1 - sed -e "s/don't use/don't just use/" dir/file2 >tmp; mv tmp dir/file2 - - # developer 1 is on a roll - cd ../../1/first-dir - echo "I need some more words" >>file1 - echo " to fill up this space" >>file1 - echo " anything else would be a disgrace" >>file1 - echo "My rhymes cross many boundries" >>dir/file2 - echo " this time it's files" >>dir/file2 - echo " a word that fits here would be something like dials" >>dir/file2 - dotest backuprecover-8 "${testcvs} -q ci -mtest" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 -done -Checking in dir/file2; -${CVSROOT_DIRNAME}/first-dir/dir/file2,v <-- file2 -new revision: 1\.3; previous revision: 1\.2 -done" - - # Save a backup copy - cp -r ${CVSROOT_DIRNAME}/first-dir ${CVSROOT_DIRNAME}/backup - - # Simulate developer 3 - cd ../.. - mkdir 3; cd 3 - dotest backuprecover-9a "${testcvs} -Q co first-dir" '' - cd first-dir - echo >>file1 - echo >>dir/file2 - echo "Developer 1 makes very lame rhymes" >>file1 - echo " I think he should quit and become a mime" >>file1 - echo "What the %*^# kind of rhyme crosses a boundry?" >>dir/file2 - echo " I think you should quit and get a job in the foundry" >>dir/file2 - dotest backuprecover-9b "${testcvs} -q ci -mtest" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.4; previous revision: 1\.3 -done -Checking in dir/file2; -${CVSROOT_DIRNAME}/first-dir/dir/file2,v <-- file2 -new revision: 1\.4; previous revision: 1\.3 -done" - - # Developer 4 so we can simulate a conflict later... - cd ../.. - mkdir 4; cd 4 - dotest backuprecover-10 "${testcvs} -Q co first-dir" '' - cd first-dir - sed -e "s/quit and/be fired so he can/" dir/file2 >tmp; mv tmp dir/file2 - - # And back to developer 1 - cd ../../1/first-dir - dotest backuprecover-11 "${testcvs} -Q update" '' - echo >>file1 - echo >>dir/file2 - echo "Oh yeah, well rhyme this" >>file1 - echo " developer three" >>file1 - echo " you want opposition" >>file1 - echo " you found some in me!" >>file1 - echo "I'll give you mimes" >>dir/file2 - echo " and foundries galore!" >>dir/file2 - echo " your head will spin" >>dir/file2 - echo " once you find what's in store!" >>dir/file2 - dotest backuprecover-12 "${testcvs} -q ci -mtest" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.5; previous revision: 1\.4 -done -Checking in dir/file2; -${CVSROOT_DIRNAME}/first-dir/dir/file2,v <-- file2 -new revision: 1\.5; previous revision: 1\.4 -done" - - # developer 3'll do a bit of work that never gets checked in - cd ../../3/first-dir - dotest backuprecover-13 "${testcvs} -Q update" '' - sed -e "s/very/some extremely/" file1 >tmp; mv tmp file1 - dotest backuprecover-14 "${testcvs} -q ci -mtest" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.6; previous revision: 1\.5 -done" - echo >>file1 - echo "Tee hee hee hee" >>file1 - echo >>dir/file2 - echo "Find what's in store?" >>dir/file2 - echo " Oh, I'm so sure!" >>dir/file2 - echo " You've got an ill, and I have the cure!" >>dir/file2 - - # Slag the original and restore it a few revisions back - rm -rf ${CVSROOT_DIRNAME}/first-dir - mv ${CVSROOT_DIRNAME}/backup ${CVSROOT_DIRNAME}/first-dir - - # Have developer 1 try an update and lose some data - # - # Feel free to imagine the horrific scream of despair - cd ../../1/first-dir - dotest backuprecover-15 "${testcvs} update" \ -"${PROG} update: Updating . -U file1 -${PROG} update: Updating dir -U dir/file2" - - # Developer 3 tries the same thing (he has an office) - # but fails without losing data since all of his files have - # uncommitted changes - cd ../../3/first-dir - dotest_fail backuprecover-16 "${testcvs} update" \ -"${PROG} update: Updating \. -${PROG} \[update aborted\]: could not find desired version 1\.6 in ${CVSROOT_DIRNAME}/first-dir/file1,v" - - # create our workspace fixin' script - cd ../.. - echo \ -"#!/bin/sh - -# This script will copy the CVS database dirs from the checked out -# version of a newly recovered repository and replace the CVS -# database dirs in a workspace with later revisions than those in the -# recovered repository -cd repos-first-dir -DATADIRS=\`find . -name CVS -print\` -cd ../first-dir -find . -name CVS -print | xargs rm -rf -for file in \${DATADIRS}; do - cp -r ../repos-first-dir/\${file} \${file} -done" >fixit - - # We only need to fix the workspaces of developers 3 and 4 - # (1 lost all her data and 2 has an update date from - # before the date the backup was made) - cd 3 - dotest backuprecover-17 \ - "${testcvs} -Q co -d repos-first-dir first-dir" '' - cd ../4 - dotest backuprecover-18 \ - "${testcvs} -Q co -d repos-first-dir first-dir" '' - sh ../fixit - cd ../3; sh ../fixit - - # (re)commit developer 3's stuff - cd first-dir - dotest backuprecover-19 "${testcvs} -q ci -mrecover/merge" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.4; previous revision: 1\.3 -done -Checking in dir/file2; -${CVSROOT_DIRNAME}/first-dir/dir/file2,v <-- file2 -new revision: 1\.4; previous revision: 1\.3 -done" - - # and we should get a conflict on developer 4's stuff - cd ../../4/first-dir - dotest backuprecover-20 "${testcvs} update" \ -"${PROG} update: Updating \. -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.3 -retrieving revision 1\.4 -Merging differences between 1\.3 and 1\.4 into file1 -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in file1 -C file1 -${PROG} update: Updating dir -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir/file2,v -retrieving revision 1\.3 -retrieving revision 1\.4 -Merging differences between 1\.3 and 1\.4 into file2 -rcsmerge: warning: conflicts during merge -${PROG} update: conflicts found in dir/file2 -C dir/file2" - sed -e \ -"/^<<<<<<</,/^=======/d -/^>>>>>>>/d" file1 >tmp; mv tmp file1 - sed -e \ -"/^<<<<<<</,/^=======/d -/^>>>>>>>/d -s/quit and/be fired so he can/" dir/file2 >tmp; mv tmp dir/file2 - dotest backuprecover-21 "${testcvs} -q ci -mrecover/merge" \ -"Checking in dir/file2; -${CVSROOT_DIRNAME}/first-dir/dir/file2,v <-- file2 -new revision: 1\.5; previous revision: 1\.4 -done" - - # go back and commit developer 2's stuff to prove it can still be done - cd ../../2/first-dir - dotest backuprecover-22 "${testcvs} -Q update" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.2 -retrieving revision 1\.4 -Merging differences between 1\.2 and 1\.4 into file1 -RCS file: ${CVSROOT_DIRNAME}/first-dir/dir/file2,v -retrieving revision 1\.2 -retrieving revision 1\.5 -Merging differences between 1\.2 and 1\.5 into file2" - dotest backuprecover-23 "${testcvs} -q ci -mtest" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.5; previous revision: 1\.4 -done -Checking in dir/file2; -${CVSROOT_DIRNAME}/first-dir/dir/file2,v <-- file2 -new revision: 1\.6; previous revision: 1\.5 -done" - - # and restore the data to developer 1 - cd ../../1/first-dir - dotest backuprecover-24 "${testcvs} -Q update" '' - - cd ../../.. - rm -r backuprecover - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - - - sshstdio) - # CVS_RSH=ssh can have a problem with a non-blocking stdio - # in some cases. So, this test is all about testing :ext: - # with CVS_RSH=ssh. The problem is that not all machines - # will necessarily have ssh available, so be prepared to - # skip this test. - - # Are we able to run find and use an ssh? - if $remote; then :; else - continue - fi - - depends_on_ssh - if test $? -eq 77; then - skip sshstdio "$skipreason" - continue - fi - - SSHSTDIO_ROOT=:ext:$host$CVSROOT_DIRNAME - - mkdir sshstdio; cd sshstdio - dotest sshstdio-1 "$testcvs -d $SSHSTDIO_ROOT -q co -l ." - mkdir first-dir - dotest sshstdio-2 "$testcvs add first-dir" \ - "Directory $CVSROOT_DIRNAME/first-dir added to the repository" - cd first-dir - a='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' - c='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' - # Generate 1024 lines of $a - cnt=0 - echo $a > aaa - while [ $cnt -lt 5 ] ; do - cnt=`expr $cnt + 1` ; - mv aaa aaa.old - cat aaa.old aaa.old aaa.old aaa.old > aaa - done - dotest sshstdio-3 "$testcvs -q add aaa" \ -"$PROG add: use .$PROG commit. to add this file permanently" - dotest sshstdio-4 "$testcvs -q ci -mcreate aaa" \ -"RCS file: $CVSROOT_DIRNAME/first-dir/aaa,v -done -Checking in aaa; -$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa -initial revision: 1\.1 -done" - # replace lines 1, 512, 513, 1024 with $c - sed 510q < aaa > aaa.old - (echo $c; cat aaa.old; echo $c; \ - echo $c; cat aaa.old; echo $c) > aaa - dotest sshstdio-5 "$testcvs -q ci -mmodify-it aaa" \ -"Checking in aaa; -$CVSROOT_DIRNAME/first-dir/aaa,v <-- aaa -new revision: 1\.2; previous revision: 1\.1 -done" - cat > wrapper.sh <<EOF -#!$TESTSHELL -exec "\$@" 2>&1 < /dev/null | cat -EOF - chmod +x wrapper.sh - ./wrapper.sh \ - $testcvs -z5 -Q diff --side-by-side -W 500 -r 1.1 -r 1.2 \ - aaa \ - |sed -e \ -'/^Write failed flushing stdout buffer\.
$/d; - /^write stdout: Broken pipe
$/d; - :retry; - /Write failed flushing stdout buffer\.
$/{ - N; - s/Write failed flushing stdout buffer\.
\n//; - b retry; -} - /write stdout: Broken pipe
$/{ - N; - s/write stdout: Broken pipe
\n//; - b retry; -}' \ - > wrapper.dif - - $testcvs -z5 -Q diff --side-by-side -W 500 -r 1.1 -r 1.2 \ - aaa > good.dif - - dotest sshstdio-6 "cmp wrapper.dif good.dif" - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd ../.. - CVS_RSH=$save_CVS_RSH; export CVS_RSH - rm -r sshstdio - rm -rf $CVSROOT_DIRNAME/first-dir - ;; - - - - parseroot2) - # Test some :ext: roots for consistancy. - if $remote; then :; else - continue - fi - - depends_on_rsh "$CVS_RSH" - if test $? -eq 77; then - skip parseroot2 "$skipreason" - continue - fi - - # Test checking out and subsequently updating with some different - # CVSROOTs. - - # A standard case, hostname:dirname. - mkdir parseroot2; cd parseroot2 - save_CVSROOT=$CVSROOT - CVSROOT=$host:$CVSROOT_DIRNAME - dotest parseroot2-1 "$testcvs -Q co CVSROOT" - cd CVSROOT - dotest parseroot2-2 "$testcvs -Q up" - cd .. - - # A degenerate remote case, just the server name and the directory - # name, with no :'s to help parsing. It can be mistaken for a - # relative directory name. - rm -r CVSROOT - CVSROOT=$host$CVSROOT_DIRNAME - dotest parseroot2-3 "$testcvs -Q co CVSROOT" - cd CVSROOT - dotest parseroot2-4 "$testcvs -Q up" - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd ../.. - CVSROOT=$save_CVSROOT - rm -r parseroot2 - ;; - - - - history) - # CVSROOT/history tests: - # history: various "cvs history" invocations - # basic2: Generating the CVSROOT/history file via CVS commands. - - # Put in some data for the history file (discarding what was - # there before). Note that this file format is fixed; the - # user may wish to analyze data from a previous version of - # CVS. If we phase out this format, it should be done - # slowly and carefully. - cat >${CVSROOT_DIRNAME}/CVSROOT/history <<EOF -O3395c677|anonymous|<remote>/*0|ccvs||ccvs -O3396c677|anonymous|<remote>/src|ccvs||src -O3397c677|kingdon|<remote>/*0|ccvs||ccvs -M339cafae|nk|<remote>|ccvs/src|1.229|sanity.sh -M339cafff|anonymous|<remote>|ccvs/src|1.23|Makefile -M339dc339|kingdon|~/work/*0|ccvs/src|1.231|sanity.sh -W33a6eada|anonymous|<remote>*4|ccvs/emx||Makefile.in -C3b235f50|kingdon|<remote>|ccvs/emx|1.3|README -M3b23af50|kingdon|~/work/*0|ccvs/doc|1.281|cvs.texinfo -EOF - dotest history-1 "${testcvs} history -e -a" \ -"O 1997-06-04 19:48 ${PLUS}0000 anonymous ccvs =ccvs= <remote>/\* -O 1997-06-05 14:00 ${PLUS}0000 anonymous ccvs =src= <remote>/\* -M 1997-06-10 01:38 ${PLUS}0000 anonymous 1\.23 Makefile ccvs/src == <remote> -W 1997-06-17 19:51 ${PLUS}0000 anonymous Makefile\.in ccvs/emx == <remote>/emx -O 1997-06-06 08:12 ${PLUS}0000 kingdon ccvs =ccvs= <remote>/\* -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 == <remote> -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 == <remote>" - - 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 == <remote>/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 == <remote> -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 == <remote>" - - 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 == <remote> -M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == <remote>" - - 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 == <remote> -M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == <remote>" - - 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 == <remote> -M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == <remote>" - - 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 == <remote> -M 1997-06-10 01:38 ${PLUS}0000 anonymous 1\.23 Makefile ccvs/src == <remote> -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 == <remote> -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 == <remote> -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= <remote>/\* -O 1997-06-05 14:00 ${PLUS}0000 anonymous ccvs =src= <remote>/\* -O 1997-06-06 08:12 ${PLUS}0000 kingdon ccvs =ccvs= <remote>/\*" - - dotest history-12 "${testcvs} history -aw -D'1970-01-01 00:00 UT'" \ -"O 1997-06-04 19:48 ${PLUS}0000 anonymous ccvs =ccvs= <remote>/\* -O 1997-06-05 14:00 ${PLUS}0000 anonymous ccvs =src= <remote>/\* -O 1997-06-06 08:12 ${PLUS}0000 kingdon ccvs =ccvs= <remote>/\*" - ;; - - big) - - # Test ability to operate on big files. Intention is to - # test various realloc'ing code in RCS_deltas, rcsgetkey, - # etc. "big" is currently defined to be 1000 lines (64000 - # bytes), which in terms of files that users will use is not - # large, merely average, but my reasoning is that this - # should be big enough to make sure realloc'ing is going on - # and that raising it a lot would start to stress resources - # on machines which run the tests, without any significant - # benefit. - - mkdir ${CVSROOT_DIRNAME}/first-dir - dotest big-1 "${testcvs} -q co first-dir" '' - cd first-dir - for i in 0 1 2 3 4 5 6 7 8 9; do - for j in 0 1 2 3 4 5 6 7 8 9; do - for k in 0 1 2 3 4 5 6 7 8 9; do - echo \ -"This is line ($i,$j,$k) which goes into the file file1 for testing" >>file1 - done - done - done - dotest big-2 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest big-3 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - cd .. - mkdir 2 - cd 2 - dotest big-4 "${testcvs} -q get first-dir" "U first-dir/file1" - cd ../first-dir - echo "add a line to the end" >>file1 - dotest big-5 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - cd ../2/first-dir - # The idea here is particularly to test the Rcs-diff response - # and the reallocing thereof, for remote. - dotest big-6 "${testcvs} -q update" "[UP] file1" - cd ../.. - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -r first-dir 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - modes) - # Test repository permissions (CVSUMASK and so on). - # Although the tests in this section "cheat" by testing - # repository permissions, which are sort of not a user-visible - # sort of thing, the modes do have user-visible consequences, - # such as whether a second user can check out the files. But - # it would be awkward to test the consequences, so we don't. - - # Solaris /bin/sh doesn't support export -n. I'm not sure - # what we can do about this, other than hope that whoever - # is running the tests doesn't have CVSUMASK set. - #export -n CVSUMASK # if unset, defaults to 002 - - umask 077 - mkdir 1; cd 1 - dotest modes-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest modes-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch aa - dotest modes-3 "${testcvs} add aa" \ -"${PROG} add: scheduling file .aa. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest modes-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aa,v -done -Checking in aa; -${CVSROOT_DIRNAME}/first-dir/aa,v <-- aa -initial revision: 1\.1 -done" - # Yawn. Cygwin. - if test -n "$remotehost"; then - dotest modes-5remotehost "$CVS_RSH $remotehost 'ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v'" \ -"-r--r--r-- .*" - else - dotest modes-5 "ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v" \ -"-r--r--r-- .*" - fi - - # Test for whether we can set the execute bit. - chmod +x aa - echo change it >>aa - dotest modes-6 "${testcvs} -q ci -m set-execute-bit" \ -"Checking in aa; -${CVSROOT_DIRNAME}/first-dir/aa,v <-- aa -new revision: 1\.2; previous revision: 1\.1 -done" - # If CVS let us update the execute bit, it would be set here. - # But it doesn't, and as far as I know that is longstanding - # CVS behavior. - # - # Yeah, yeah. Search for "Cygwin". - if test -n "$remotehost"; then - dotest modes-7remotehost "$CVS_RSH $remotehost 'ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v'" \ -"-r--r--r-- .*" - else - dotest modes-7 "ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v" \ -"-r--r--r-- .*" - fi - - # OK, now manually change the modes and see what happens. - # - # Cygwin, already. - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod g=r,o= ${CVSROOT_DIRNAME}/first-dir/aa,v" - else - chmod g=r,o= ${CVSROOT_DIRNAME}/first-dir/aa,v - fi - echo second line >>aa - dotest modes-7a "${testcvs} -q ci -m set-execute-bit" \ -"Checking in aa; -${CVSROOT_DIRNAME}/first-dir/aa,v <-- aa -new revision: 1\.3; previous revision: 1\.2 -done" - # Cygwin. - if test -n "$remotehost"; then - dotest modes-7bremotehost "$CVS_RSH $remotehost 'ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v'" \ -"-r--r----- .*" - else - dotest modes-7b "ls -l ${CVSROOT_DIRNAME}/first-dir/aa,v" \ -"-r--r----- .*" - fi - - CVSUMASK=007 - export CVSUMASK - touch ab - # Might as well test the execute bit too. - chmod +x ab - dotest modes-8 "${testcvs} add ab" \ -"${PROG} add: scheduling file .ab. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest modes-9 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/ab,v -done -Checking in ab; -${CVSROOT_DIRNAME}/first-dir/ab,v <-- ab -initial revision: 1\.1 -done" - if $remote; then - # The problem here is that the CVSUMASK environment variable - # needs to be set on the server (e.g. .bashrc). This is, of - # course, bogus, but that is the way it is currently. - if test -n "$remotehost"; then - dotest modes-10remotehost "$CVS_RSH $remotehost 'ls -l ${CVSROOT_DIRNAME}/first-dir/ab,v'" \ -"-r--r--r--.*" - else - dotest modes-10r "ls -l ${CVSROOT_DIRNAME}/first-dir/ab,v" \ -"-r-xr-x---.*" "-r-xr-xr-x.*" - fi - else - dotest modes-10 "ls -l ${CVSROOT_DIRNAME}/first-dir/ab,v" \ -"-r-xr-x---.*" - fi - - # OK, now add a file on a branch. Check that the mode gets - # set the same way (it is a different code path in CVS). - dotest modes-11 "${testcvs} -q tag -b br" 'T aa -T ab' - dotest modes-12 "$testcvs -q update -r br" \ -'[UP] aa -U ab' - touch ac - dotest modes-13 "${testcvs} add ac" \ -"${PROG} add: scheduling file .ac. for addition on branch .br. -${PROG} add: use .${PROG} commit. to add this file permanently" - # Not sure it really makes sense to refer to a "previous revision" - # when we are just now adding the file; as far as I know - # that is longstanding CVS behavior, for what it's worth. - dotest modes-14 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/ac,v -done -Checking in ac; -${CVSROOT_DIRNAME}/first-dir/Attic/ac,v <-- ac -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - if $remote; then - # The problem here is that the CVSUMASK environment variable - # needs to be set on the server (e.g. .bashrc). This is, of - # course, bogus, but that is the way it is currently. The - # first match is for the :ext: method (where the CVSUMASK - # won't be set), while the second is for the :fork: method - # (where it will be). - if test -n "$remotehost"; then - dotest modes-15r \ -"$CVS_RSH $remotehost 'ls -l ${CVSROOT_DIRNAME}/first-dir/Attic/ac,v'" \ -"-r--r--r--.*" - else - dotest modes-15r \ -"ls -l ${CVSROOT_DIRNAME}/first-dir/Attic/ac,v" \ -"-r--r--r--.*" "-r--r-----.*" - fi - else - dotest modes-15 \ -"ls -l ${CVSROOT_DIRNAME}/first-dir/Attic/ac,v" \ -"-r--r-----.*" - fi - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - # Perhaps should restore the umask and CVSUMASK. But the other - # tests "should" not care about them... - ;; - - modes2) - # More tests of file permissions in the working directory - # and that sort of thing. - - # The usual setup, file first-dir/aa with two revisions. - mkdir 1; cd 1 - dotest modes2-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest modes2-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch aa - dotest modes2-3 "${testcvs} add aa" \ -"${PROG} add: scheduling file .aa. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest modes2-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aa,v -done -Checking in aa; -${CVSROOT_DIRNAME}/first-dir/aa,v <-- aa -initial revision: 1\.1 -done" - echo "more money" >> aa - dotest modes2-5 "${testcvs} -q ci -m add" \ -"Checking in aa; -${CVSROOT_DIRNAME}/first-dir/aa,v <-- aa -new revision: 1\.2; previous revision: 1\.1 -done" - - # OK, here is the test. The idea is to see what - # No_Difference does if it can't open the file. - # If we don't change the st_mtime, CVS doesn't even try to read - # the file. Note that some versions of "touch" require that we - # do this while the file is still writable. - touch aa - chmod a= aa - # Don't try this when permissions are broken, as with Cygwin. - if ls ${CVSROOT_DIRNAME}/first-dir >/dev/null 2>&1; then :; else - dotest_fail modes2-6 "${testcvs} -q update -r 1.1 aa" \ -"${PROG} \[update aborted\]: cannot open file aa for comparing: Permission denied" \ -"${PROG} \[update aborted\]: reading aa: Permission denied" - fi - - chmod u+rwx aa - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - modes3) - # Repository permissions. Particularly, what happens if we - # can't read/write in the repository. - # TODO: the case where we can access the repository, just not - # the attic (may that one can remain a fatal error, seems less - # useful for access control). - mkdir 1; cd 1 - dotest modes3-1 "${testcvs} -q co -l ." '' - mkdir first-dir second-dir - dotest modes3-2 "${testcvs} add first-dir second-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository -Directory ${CVSROOT_DIRNAME}/second-dir added to the repository" - touch first-dir/aa second-dir/ab - dotest modes3-3 "${testcvs} add first-dir/aa second-dir/ab" \ -"${PROG} add: scheduling file .first-dir/aa. for addition -${PROG} add: scheduling file .second-dir/ab. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest modes3-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aa,v -done -Checking in first-dir/aa; -${CVSROOT_DIRNAME}/first-dir/aa,v <-- aa -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/second-dir/ab,v -done -Checking in second-dir/ab; -${CVSROOT_DIRNAME}/second-dir/ab,v <-- ab -initial revision: 1\.1 -done" - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod a= ${CVSROOT_DIRNAME}/first-dir" - else - chmod a= ${CVSROOT_DIRNAME}/first-dir - fi - if ls ${CVSROOT_DIRNAME}/first-dir >/dev/null 2>&1; then - # Avoid this test under Cygwin since permissions work differently - # there. - # - # This test also gets avoided under Mac OS X since the system `ls' - # is broken and exits with a 0 status despite the permission - # denied error. - if test -n "$remotehost"; then - cygwin_hack=false - else - cygwin_hack=: - fi - else - cygwin_hack=false - fi - - cd $TESTDIR/1 - if $cygwin_hack; then :; else - dotest modes3-5 "${testcvs} update" \ -"${PROG} update: Updating \. -${PROG} update: Updating first-dir -${PROG} update: cannot open directory ${CVSROOT_DIRNAME}/first-dir: Permission denied -${PROG} update: skipping directory first-dir -${PROG} update: Updating second-dir" - fi - - # OK, I can see why one might say the above case could be a - # fatal error, because normally users without access to first-dir - # won't have it in their working directory. But the next - # one is more of a problem if it is fatal. - # - # The second text string below is for Cygwin again, and again it - # should really be XFAIL under Cygwin, but for now deal with the - # passing opendir by accepting the alternate string. - rm -r first-dir - dotest modes3-6 "${testcvs} update -dP" \ -"${PROG} update: Updating . -${PROG} update: Updating CVSROOT -U ${DOTSTAR} -${PROG} update: Updating first-dir -${PROG} update: cannot open directory ${CVSROOT_DIRNAME}/first-dir: Permission denied -${PROG} update: skipping directory first-dir -${PROG} update: Updating second-dir" \ -"${PROG} update: Updating . -${PROG} update: Updating CVSROOT -U ${DOTSTAR} -${PROG} update: Updating first-dir -${PROG} update: Updating second-dir" - - cd .. - rm -r 1 - chmod u+rwx ${CVSROOT_DIRNAME}/first-dir - rm -rf ${CVSROOT_DIRNAME}/first-dir ${CVSROOT_DIRNAME}/second-dir - ;; - - stamps) - # Test timestamps. - mkdir 1; cd 1 - dotest stamps-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest stamps-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch aa - echo '$''Id$' >kw - # Cygwin, *cough*, puts the year in the time column until the minute - # is no longer the current minute. Sleep 60 seconds to avoid this - # problem. - sleep 60 - ls -l aa >${TESTDIR}/1/stamp.aa.touch - ls -l kw >${TESTDIR}/1/stamp.kw.touch - # "sleep 1" would suffice if we could assume ls --full-time, but - # that is as far as I know unique to GNU ls. Is there some POSIX.2 - # way to get the timestamp of a file, including the seconds? - sleep 60 - dotest stamps-3 "${testcvs} add aa kw" \ -"${PROG} add: scheduling file .aa. for addition -${PROG} add: scheduling file .kw. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - ls -l aa >${TESTDIR}/1/stamp.aa.add - ls -l kw >${TESTDIR}/1/stamp.kw.add - # "cvs add" should not muck with the timestamp. - dotest stamps-4aa \ -"cmp ${TESTDIR}/1/stamp.aa.touch ${TESTDIR}/1/stamp.aa.add" '' - dotest stamps-4kw \ -"cmp ${TESTDIR}/1/stamp.kw.touch ${TESTDIR}/1/stamp.kw.add" '' - sleep 60 - dotest stamps-5 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aa,v -done -Checking in aa; -${CVSROOT_DIRNAME}/first-dir/aa,v <-- aa -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/kw,v -done -Checking in kw; -${CVSROOT_DIRNAME}/first-dir/kw,v <-- kw -initial revision: 1\.1 -done" - # Cygwin, *cough*, puts the year in the time column until the minute - # is no longer the current minute. Sleep 60 seconds to avoid this - # problem. - sleep 60 - ls -l aa >${TESTDIR}/1/stamp.aa.ci - ls -l kw >${TESTDIR}/1/stamp.kw.ci - # If there are no keywords, "cvs ci" leaves the timestamp alone - # If there are, it sets the timestamp to the date of the commit. - # I'm not sure how logical this is, but it is intentional. - # If we wanted to get fancy we would make sure the time as - # reported in "cvs log kw" matched stamp.kw.ci. But that would - # be a lot of work. - dotest stamps-6aa \ - "cmp ${TESTDIR}/1/stamp.aa.add ${TESTDIR}/1/stamp.aa.ci" '' - if cmp ${TESTDIR}/1/stamp.kw.add ${TESTDIR}/1/stamp.kw.ci >/dev/null - then - fail stamps-6kw - else - pass stamps-6kw - fi - cd ../.. - sleep 60 - mkdir 2 - cd 2 - dotest stamps-7 "${testcvs} -q get first-dir" "U first-dir/aa -U first-dir/kw" - cd first-dir - ls -l aa >${TESTDIR}/1/stamp.aa.get - ls -l kw >${TESTDIR}/1/stamp.kw.get - # On checkout, CVS should set the timestamp to the date that the - # file was committed. Could check that the time as reported in - # "cvs log aa" matches stamp.aa.get, but that would be a lot of - # work. - if cmp ${TESTDIR}/1/stamp.aa.ci ${TESTDIR}/1/stamp.aa.get >/dev/null - then - fail stamps-8aa - else - pass stamps-8aa - fi - dotest stamps-8kw \ - "cmp ${TESTDIR}/1/stamp.kw.ci ${TESTDIR}/1/stamp.kw.get" '' - - # Now we want to see what "cvs update" does. - sleep 60 - echo add a line >>aa - echo add a line >>kw - dotest stamps-9 "${testcvs} -q ci -m change-them" \ -"Checking in aa; -${CVSROOT_DIRNAME}/first-dir/aa,v <-- aa -new revision: 1\.2; previous revision: 1\.1 -done -Checking in kw; -${CVSROOT_DIRNAME}/first-dir/kw,v <-- kw -new revision: 1\.2; previous revision: 1\.1 -done" - - # Cygwin, *cough*, puts the year in the time column until the minute - # is no longer the current minute. Sleep 60 seconds to avoid this - # problem. - sleep 60 - ls -l aa >${TESTDIR}/1/stamp.aa.ci2 - ls -l kw >${TESTDIR}/1/stamp.kw.ci2 - cd ../.. - cd 1/first-dir - sleep 60 - dotest stamps-10 "${testcvs} -q update" '[UP] aa -[UP] kw' - # this doesn't serve any function other than being able to - # look at it manually, as we have no machinery for dates being - # newer or older than other dates. - date >${TESTDIR}/1/stamp.debug.update - ls -l aa >${TESTDIR}/1/stamp.aa.update - ls -l kw >${TESTDIR}/1/stamp.kw.update - # stamp.aa.update and stamp.kw.update should both be approximately - # the same as stamp.debug.update. Perhaps we could be testing - # this in a more fancy fashion by "touch stamp.before" before - # stamps-10, "touch stamp.after" after, and then using ls -t - # to check them. But for now we just make sure that the *.update - # stamps differ from the *.ci2 ones. - # As for the rationale, this is so that if one updates and gets - # a new revision, then "make" will be sure to regard those files - # as newer than .o files which may be sitting around. - if cmp ${TESTDIR}/1/stamp.aa.update ${TESTDIR}/1/stamp.aa.ci2 \ - >/dev/null - then - fail stamps-11aa - else - pass stamps-11aa - fi - if cmp ${TESTDIR}/1/stamp.kw.update ${TESTDIR}/1/stamp.kw.ci2 \ - >/dev/null - then - fail stamps-11kw - else - pass stamps-11kw - fi - - cd ../.. - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -r 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - perms) - # short cut around checking out and committing CVSROOT - rm -f ${CVSROOT_DIRNAME}/CVSROOT/config - echo 'PreservePermissions=yes' > ${CVSROOT_DIRNAME}/CVSROOT/config - chmod 444 ${CVSROOT_DIRNAME}/CVSROOT/config - - mkdir 1; cd 1 - dotest perms-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest perms-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - touch foo - chmod 431 foo - dotest perms-3 "${testcvs} add foo" \ -"${PROG} add: scheduling file .foo. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest perms-4 "${testcvs} -q ci -m ''" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/foo,v -done -Checking in foo; -${CVSROOT_DIRNAME}/first-dir/foo,v <-- foo -initial revision: 1\.1 -done" - - # Test checking out files with different permissions. - cd ../.. - mkdir 2; cd 2 - dotest perms-5 "${testcvs} -q co first-dir" "U first-dir/foo" - cd first-dir - if $remote; then :; else - # PreservePermissions not yet implemented for remote. - dotest perms-6 "ls -l foo" "-r---wx--x .* foo" - fi - - cd ../.. - rm -rf 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - - rm -f ${CVSROOT_DIRNAME}/CVSROOT/config - touch ${CVSROOT_DIRNAME}/CVSROOT/config - chmod 444 ${CVSROOT_DIRNAME}/CVSROOT/config - ;; - - symlinks) - # short cut around checking out and committing CVSROOT - rm -f ${CVSROOT_DIRNAME}/CVSROOT/config - echo 'PreservePermissions=yes' > ${CVSROOT_DIRNAME}/CVSROOT/config - chmod 444 ${CVSROOT_DIRNAME}/CVSROOT/config - - mkdir 1; cd 1 - dotest symlinks-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest symlinks-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - dotest symlinks-2.1 "ln -s ${TESTDIR}/fumble slink" "" - dotest symlinks-3 "${testcvs} add slink" \ -"${PROG} add: scheduling file .slink. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - if $remote; then - # Remote doesn't implement PreservePermissions, and in its - # absence the correct behavior is to follow the symlink. - dotest_fail symlinks-4r "${testcvs} -q ci -m ''" \ -"${PROG} \[commit aborted\]: reading slink: No such file or directory" - else - dotest symlinks-4 "${testcvs} -q ci -m ''" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/slink,v -done -Checking in slink; -${CVSROOT_DIRNAME}/first-dir/slink,v <-- slink -initial revision: 1\.1 -done" - - # Test checking out symbolic links. - cd ../.. - mkdir 2; cd 2 - dotest symlinks-5 "${testcvs} -q co first-dir" "U first-dir/slink" - cd first-dir - dotest symlinks-6 "ls -l slink" \ -"l[rwx\-]* .* slink -> ${TESTDIR}/fumble" - fi - - cd ../.. - rm -rf 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - - rm -f ${CVSROOT_DIRNAME}/CVSROOT/config - touch ${CVSROOT_DIRNAME}/CVSROOT/config - chmod 444 ${CVSROOT_DIRNAME}/CVSROOT/config - ;; - - symlinks2) - # Symlinks in working directory without PreservePermissions. - # Also see: symlinks: with PreservePermissions - # rcslib-symlink-*: symlinks in repository. - mkdir 1; cd 1 - dotest symlinks2-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest symlinks2-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - echo nonsymlink > slink - dotest symlinks2-3 "${testcvs} add slink" \ -"${PROG} add: scheduling file .slink. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest symlinks2-4 "${testcvs} -q ci -m ''" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/slink,v -done -Checking in slink; -${CVSROOT_DIRNAME}/first-dir/slink,v <-- slink -initial revision: 1\.1 -done" - rm slink - # Choose name cvslog.* so it is in default ignore list. - echo second file >cvslog.file2 - dotest symlinks2-5 "ln -s cvslog.file2 slink" "" - dotest symlinks2-6 "${testcvs} -q ci -m linkify" \ -"Checking in slink; -${CVSROOT_DIRNAME}/first-dir/slink,v <-- slink -new revision: 1\.2; previous revision: 1\.1 -done" - dotest symlinks2-7 "${testcvs} -q update -r 1.1 slink" "[UP] slink" - dotest symlinks2-8 "cat slink" "nonsymlink" - dotest symlinks2-9 "ls -l slink" "-[-rwx]* .* slink" - cd ../.. - - rm -rf 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - hardlinks) - # short cut around checking out and committing CVSROOT - rm -f ${CVSROOT_DIRNAME}/CVSROOT/config - echo 'PreservePermissions=yes' > ${CVSROOT_DIRNAME}/CVSROOT/config - chmod 444 ${CVSROOT_DIRNAME}/CVSROOT/config - - mkdir 1; cd 1 - dotest hardlinks-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest hardlinks-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - # Make up some ugly filenames, to test that they get - # encoded properly in the delta nodes. Note that `dotest' screws - # up if some arguments have embedded spaces. - if touch aaaa - then - pass hardlinks-2.1 - else - fail hardlinks-2.1 - fi - - if ln aaaa b.b.b.b - then - pass hardlinks-2.2 - else - fail hardlinks-2.2 - fi - - if ln aaaa 'dd dd dd' - then - pass hardlinks-2.3 - else - fail hardlinks-2.3 - fi - - dotest hardlinks-3 "${testcvs} add [abd]*" \ -"${PROG} add: scheduling file .aaaa. for addition -${PROG} add: scheduling file .b\.b\.b\.b. for addition -${PROG} add: scheduling file .dd dd dd. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest hardlinks-4 "${testcvs} -q ci -m ''" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaaa,v -done -Checking in aaaa; -${CVSROOT_DIRNAME}/first-dir/aaaa,v <-- aaaa -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/b\.b\.b\.b,v -done -Checking in b\.b\.b\.b; -${CVSROOT_DIRNAME}/first-dir/b\.b\.b\.b,v <-- b\.b\.b\.b -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/dd dd dd,v -done -Checking in dd dd dd; -${CVSROOT_DIRNAME}/first-dir/dd dd dd,v <-- dd dd dd -initial revision: 1\.1 -done" - # Test checking out hardlinked files. - cd ../.. - mkdir 2; cd 2 - if $remote; then - # Remote does not implement PreservePermissions. - dotest hardlinks-5r "${testcvs} -q co first-dir" \ -"U first-dir/aaaa -U first-dir/b\.b\.b\.b -U first-dir/dd dd dd" - cd first-dir - dotest hardlinks-6r "ls -l [abd]*" \ -"-[rwx\-]* *1 .* aaaa --[rwx\-]* *1 .* b\.b\.b\.b --[rwx\-]* *1 .* dd dd dd" - else - dotest hardlinks-5 "${testcvs} -q co first-dir" \ -"U first-dir/aaaa -U first-dir/b\.b\.b\.b -U first-dir/dd dd dd" - cd first-dir - # To make sure that the files are properly hardlinked, it - # would be nice to do `ls -i' and make sure all the inodes - # match. But I think that would require expr to support - # tagged regexps, and I don't think we can rely on that. - # So instead we just see that each file has the right - # number of links. -twp - dotest hardlinks-6 "ls -l [abd]*" \ -"-[rwx\-]* *3 .* aaaa --[rwx\-]* *3 .* b\.b\.b\.b --[rwx\-]* *3 .* dd dd dd" - fi - - cd ../.. - rm -rf 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - - rm -f ${CVSROOT_DIRNAME}/CVSROOT/config - touch ${CVSROOT_DIRNAME}/CVSROOT/config - chmod 444 ${CVSROOT_DIRNAME}/CVSROOT/config - ;; - - sticky) - # More tests of sticky tags, particularly non-branch sticky tags. - # See many tests (e.g. multibranch) for ordinary sticky tag - # operations such as adding files on branches. - # See "head" test for interaction between stick tags and HEAD. - mkdir 1; cd 1 - dotest sticky-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest sticky-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - touch file1 - dotest sticky-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest sticky-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - dotest sticky-5 "${testcvs} -q tag tag1" "T file1" - echo add a line >>file1 - dotest sticky-6 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - dotest sticky-7 "${testcvs} -q update -r tag1" "[UP] file1" - dotest sticky-8 "cat file1" '' - dotest sticky-9 "${testcvs} -q update" '' - dotest sticky-10 "cat file1" '' - touch file2 - dotest_fail sticky-11 "${testcvs} add file2" \ -"${PROG} add: cannot add file on non-branch tag tag1" - dotest sticky-12 "${testcvs} -q update -A" "[UP] file1 -${QUESTION} file2" "${QUESTION} file2 -[UP] file1" - dotest sticky-13 "${testcvs} add file2" \ -"${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest sticky-14 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - - # Now back to tag1 - dotest sticky-15 "${testcvs} -q update -r tag1" "[UP] file1 -${PROG} update: file2 is no longer in the repository" - - rm file1 - dotest sticky-16 "${testcvs} rm file1" \ -"${PROG} remove: scheduling .file1. for removal -${PROG} remove: use .${PROG} commit. to remove this file permanently" - # Hmm, this command seems to silently remove the tag from - # the file. This appears to be intentional. - # The silently part especially strikes me as odd, though. - dotest sticky-17 "${testcvs} -q ci -m remove-it" "" - dotest sticky-18 "${testcvs} -q update -A" "U file1 -U file2" - dotest sticky-19 "${testcvs} -q update -r tag1" \ -"${PROG} update: file1 is no longer in the repository -${PROG} update: file2 is no longer in the repository" - dotest sticky-20 "${testcvs} -q update -A" "U file1 -U file2" - - # Now try with a numeric revision. - dotest sticky-21 "${testcvs} -q update -r 1.1 file1" "U file1" - dotest sticky-22 "${testcvs} rm -f file1" \ -"${PROG} remove: cannot remove file .file1. which has a numeric sticky tag of .1\.1." - # The old behavior was that remove allowed this and then commit - # gave an error, which was somewhat hard to clear. I mean, you - # could get into a long elaborate discussion of this being a - # conflict and two ways to resolve it, but I don't really see - # why CVS should have a concept of conflict that arises, not from - # parallel development, but from CVS's own sticky tags. - - # Ditto with a sticky date. - # - # I'm kind of surprised that the "file1 was lost" doesn't crop - # up elsewhere in the testsuite. It is a long-standing - # discrepency between local and remote CVS and should probably - # be cleaned up at some point. - dotest sticky-23 "${testcvs} -q update -Dnow file1" \ -"${PROG} update: warning: file1 was lost -U file1" "U file1" - dotest sticky-24 "${testcvs} rm -f file1" \ -"${PROG} remove: cannot remove file .file1. which has a sticky date of .[0-9.]*." - - dotest sticky-25 "${testcvs} -q update -A" \ -"${PROG} update: warning: file1 was lost -U file1" "U file1" - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - keyword) - # Test keyword expansion. - # Various other tests relate to our ability to correctly - # set the keyword expansion mode. - # "binfiles" tests "cvs admin -k". - # "binfiles" and "binfiles2" test "cvs add -k". - # "rdiff" tests "cvs co -k". - # "binfiles" (and this test) test "cvs update -k". - # "binwrap" tests setting the mode from wrappers. - # "keyword2" tests "cvs update -kk -j" with text and binary files - # I don't think any test is testing "cvs import -k". - # Other keyword expansion tests: - # keywordlog - $Log. - mkdir 1; cd 1 - dotest keyword-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest keyword-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - echo '$''Author$' > file1 - echo '$''Date$' >> file1 - echo '$''Header$' >> file1 - echo '$''Id$' >> file1 - echo '$''Locker$' >> file1 - echo '$''Name$' >> file1 - echo '$''RCSfile$' >> file1 - echo '$''Revision$' >> file1 - echo '$''Source$' >> file1 - echo '$''State$' >> file1 - echo '$''Nonkey$' >> file1 - # Omit the trailing dollar sign - echo '$''Date' >> file1 - # Put two keywords on one line - echo '$''State$' '$''State$' >> file1 - # Use a header for Log - echo 'xx $''Log$' >> file1 - - dotest keyword-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest keyword-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - dotest keyword-5 "cat file1" \ -'\$'"Author: ${username} "'\$'" -"'\$'"Date: [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] "'\$'" -"'\$'"Header: ${CVSROOT_DIRNAME}/first-dir/file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'" -"'\$'"Id: file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'" -"'\$'"Locker: "'\$'" -"'\$'"Name: "'\$'" -"'\$'"RCSfile: file1,v "'\$'" -"'\$'"Revision: 1\.1 "'\$'" -"'\$'"Source: ${CVSROOT_DIRNAME}/first-dir/file1,v "'\$'" -"'\$'"State: Exp "'\$'" -"'\$'"Nonkey"'\$'" -"'\$'"Date -"'\$'"State: Exp "'\$'" "'\$'"State: Exp "'\$'" -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.1 [0-9/]* [0-9:]* ${username} -xx add -xx" - - # Use cvs admin to lock the RCS file in order to check -kkvl - # vs. -kkv. CVS does not normally lock RCS files, but some - # people use cvs admin to enforce reserved checkouts. - dotest keyword-6 "${testcvs} admin -l file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -1\.1 locked -done" - - dotest keyword-7 "$testcvs update -kkv file1" '[UP] file1' - dotest keyword-8 "cat file1" \ -'\$'"Author: ${username} "'\$'" -"'\$'"Date: [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] "'\$'" -"'\$'"Header: ${CVSROOT_DIRNAME}/first-dir/file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'" -"'\$'"Id: file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'" -"'\$'"Locker: "'\$'" -"'\$'"Name: "'\$'" -"'\$'"RCSfile: file1,v "'\$'" -"'\$'"Revision: 1\.1 "'\$'" -"'\$'"Source: ${CVSROOT_DIRNAME}/first-dir/file1,v "'\$'" -"'\$'"State: Exp "'\$'" -"'\$'"Nonkey"'\$'" -"'\$'"Date -"'\$'"State: Exp "'\$'" "'\$'"State: Exp "'\$'" -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.1 [0-9/]* [0-9:]* ${username} -xx add -xx" - - dotest keyword-9 "$testcvs update -kkvl file1" '[UP] file1' - dotest keyword-10 "cat file1" \ -'\$'"Author: ${username} "'\$'" -"'\$'"Date: [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] "'\$'" -"'\$'"Header: ${CVSROOT_DIRNAME}/first-dir/file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp ${username} "'\$'" -"'\$'"Id: file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp ${username} "'\$'" -"'\$'"Locker: ${username} "'\$'" -"'\$'"Name: "'\$'" -"'\$'"RCSfile: file1,v "'\$'" -"'\$'"Revision: 1\.1 "'\$'" -"'\$'"Source: ${CVSROOT_DIRNAME}/first-dir/file1,v "'\$'" -"'\$'"State: Exp "'\$'" -"'\$'"Nonkey"'\$'" -"'\$'"Date -"'\$'"State: Exp "'\$'" "'\$'"State: Exp "'\$'" -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.1 [0-9/]* [0-9:]* ${username} -xx add -xx" - - dotest keyword-11 "${testcvs} update -kk file1" '[UP] file1' - dotest keyword-12 "cat file1" \ -'\$'"Author"'\$'" -"'\$'"Date"'\$'" -"'\$'"Header"'\$'" -"'\$'"Id"'\$'" -"'\$'"Locker"'\$'" -"'\$'"Name"'\$'" -"'\$'"RCSfile"'\$'" -"'\$'"Revision"'\$'" -"'\$'"Source"'\$'" -"'\$'"State"'\$'" -"'\$'"Nonkey"'\$'" -"'\$'"Date -"'\$'"State"'\$'" "'\$'"State"'\$'" -xx "'\$'"Log"'\$'" -xx Revision 1\.1 [0-9/]* [0-9:]* ${username} -xx add -xx" - - dotest keyword-13 "$testcvs update -kv file1" '[UP] file1' - dotest keyword-14 "cat file1" \ -"${username} -[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] -${CVSROOT_DIRNAME}/first-dir/file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp -file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp - - -file1,v -1\.1 -${CVSROOT_DIRNAME}/first-dir/file1,v -Exp -"'\$'"Nonkey"'\$'" -"'\$'"Date -Exp Exp -xx file1,v -xx Revision 1\.1 [0-9/]* [0-9:]* ${username} -xx add -xx" - - dotest keyword-15 "${testcvs} update -ko file1" "U file1" - dotest keyword-16 "cat file1" \ -'\$'"Author"'\$'" -"'\$'"Date"'\$'" -"'\$'"Header"'\$'" -"'\$'"Id"'\$'" -"'\$'"Locker"'\$'" -"'\$'"Name"'\$'" -"'\$'"RCSfile"'\$'" -"'\$'"Revision"'\$'" -"'\$'"Source"'\$'" -"'\$'"State"'\$'" -"'\$'"Nonkey"'\$'" -"'\$'"Date -"'\$'"State"'\$'" "'\$'"State"'\$'" -xx "'\$'"Log"'\$' - - # Test the Name keyword. First go back to normal expansion. - - dotest keyword-17 "${testcvs} update -A file1" "U file1" - - echo '$''Name$' > file1 - dotest keyword-18 "${testcvs} ci -m modify file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - dotest keyword-19 "${testcvs} -q tag tag1" "T file1" - echo "change" >> file1 - dotest keyword-20 "${testcvs} -q ci -m mod2 file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 -done" - - # Prior to 1.11.23, remote CVS would fail the patch checksum test - # and refetch the file here, failing this test. - dotest keyword-21 "$testcvs -q update -r tag1" 'U file1' - - dotest keyword-22 "cat file1" '\$'"Name: tag1 "'\$' - - # The update used to fail the first time with a checksum failure - # here, then the server would send the whole failure. This was fixed - # in 1.11.23. - dotest keyword-23 "$testcvs update -A file1" "U file1" - dotest keyword-24 "cat file1" '\$'"Name: "'\$'" -change" - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - keywordlog) - # Test the Log keyword. - mkdir 1; cd 1 - dotest keywordlog-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest keywordlog-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - echo initial >file1 - dotest keywordlog-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - - # See "rmadd" for a list of other tests of cvs ci -r. - dotest keywordlog-4 "${testcvs} -q ci -r 1.3 -m add file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.3 -done" - - cd ../.. - mkdir 2; cd 2 - dotest keywordlog-4a "${testcvs} -q co first-dir" "U first-dir/file1" - cd ../1/first-dir - - echo 'xx $''Log$' >> file1 - cat >${TESTDIR}/comment.tmp <<EOF -First log line -Second log line -EOF - # As with rmadd-25, "cvs ci -r" sets a sticky tag. - dotest_fail keywordlog-4b \ -"${testcvs} ci -F ${TESTDIR}/comment.tmp file1" \ -"${PROG} commit: sticky tag .1\.3. for file .file1. is not a branch -${PROG} \[commit aborted\]: correct above errors first!" - dotest keywordlog-4c "${testcvs} -q update -A" "M file1" - - dotest keywordlog-5 "${testcvs} ci -F ${TESTDIR}/comment.tmp file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.4; previous revision: 1\.3 -done" - rm -f ${TESTDIR}/comment.tmp - dotest keywordlog-6 "${testcvs} -q tag -b br" "T file1" - dotest keywordlog-7 "cat file1" \ -"initial -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.4 [0-9/]* [0-9:]* ${username} -xx First log line -xx Second log line -xx" - - cd ../../2/first-dir - dotest keywordlog-8 "${testcvs} -q update" "[UP] file1" - dotest keywordlog-9 "cat file1" \ -"initial -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.4 [0-9/]* [0-9:]* ${username} -xx First log line -xx Second log line -xx" - cd ../../1/first-dir - - echo "change" >> file1 - dotest keywordlog-10 "${testcvs} ci -m modify file1" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.5; previous revision: 1\.4 -done" - dotest keywordlog-11 "cat file1" \ -"initial -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.5 [0-9/]* [0-9:]* ${username} -xx modify -xx -xx Revision 1\.4 [0-9/]* [0-9:]* ${username} -xx First log line -xx Second log line -xx -change" - - cd ../../2/first-dir - dotest keywordlog-12 "${testcvs} -q update" "[UP] file1" - dotest keywordlog-13 "cat file1" \ -"initial -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.5 [0-9/]* [0-9:]* ${username} -xx modify -xx -xx Revision 1\.4 [0-9/]* [0-9:]* ${username} -xx First log line -xx Second log line -xx -change" - - cd ../../1/first-dir - dotest keywordlog-14 "${testcvs} -q update -r br" "[UP] file1" - echo br-change >>file1 - dotest keywordlog-15 "${testcvs} -q ci -m br-modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.4\.2\.1; previous revision: 1\.4 -done" - dotest keywordlog-16 "cat file1" \ -"initial -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.4\.2\.1 [0-9/]* [0-9:]* ${username} -xx br-modify -xx -xx Revision 1\.4 [0-9/]* [0-9:]* ${username} -xx First log line -xx Second log line -xx -br-change" - cd ../../2/first-dir - dotest keywordlog-17 "${testcvs} -q update -r br" "[UP] file1" - dotest keywordlog-18 "cat file1" \ -"initial -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.4\.2\.1 [0-9/]* [0-9:]* ${username} -xx br-modify -xx -xx Revision 1\.4 [0-9/]* [0-9:]* ${username} -xx First log line -xx Second log line -xx -br-change" - cd ../.. - dotest keywordlog-19 "${testcvs} -q co -p -r br first-dir/file1" \ -"initial -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.4\.2\.1 [0-9/]* [0-9:]* ${username} -xx br-modify -xx -xx Revision 1\.4 [0-9/]* [0-9:]* ${username} -xx First log line -xx Second log line -xx -br-change" - dotest keywordlog-20 "${testcvs} -q co -p first-dir/file1" \ -"initial -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.5 [0-9/]* [0-9:]* ${username} -xx modify -xx -xx Revision 1\.4 [0-9/]* [0-9:]* ${username} -xx First log line -xx Second log line -xx -change" - dotest keywordlog-21 "${testcvs} -q co -p -r 1.4 first-dir/file1" \ -"initial -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.4 [0-9/]* [0-9:]* ${username} -xx First log line -xx Second log line -xx" - - cd 2/first-dir - # OK, the basic rule for keyword expansion is that it - # happens on checkout. And the rule for annotate is that - # it annotates a checked-in revision, rather than a checked-out - # file. So, although it is kind of confusing that the latest - # revision does not appear in the annotated output, and the - # annotated output does not quite match what you'd get with - # update or checkout, the behavior is more or less logical. - # The same issue occurs with annotate and other keywords, - # I think, although it is particularly noticeable for $Log. - dotest keywordlog-22 "${testcvs} ann -r br file1" \ -" -Annotations for file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.3 ($username8 *[0-9a-zA-Z-]*): initial -1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): xx "'\$'"Log: file1,v "'\$'" -1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): xx Revision 1\.4 [0-9/]* [0-9:]* $username -1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): xx First log line -1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): xx Second log line -1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): xx -1\.4\.2\.1 ($username8 *[0-9a-zA-Z-]*): br-change" - dotest keywordlog-23 "${testcvs} ann -r HEAD file1" \ -" -Annotations for file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.3 ($username8 *[0-9a-zA-Z-]*): initial -1\.5 ($username8 *[0-9a-zA-Z-]*): xx "'\$'"Log: file1,v "'\$'" -1\.5 ($username8 *[0-9a-zA-Z-]*): xx Revision 1\.4 [0-9/]* [0-9:]* $username -1\.5 ($username8 *[0-9a-zA-Z-]*): xx First log line -1\.5 ($username8 *[0-9a-zA-Z-]*): xx Second log line -1\.5 ($username8 *[0-9a-zA-Z-]*): xx -1\.5 ($username8 *[0-9a-zA-Z-]*): change" - cd ../.. - - # - # test the operation of 'admin -o' in conjunction with keywords - # (especially Log - this used to munge the RCS file for all time) - # - - dotest keywordlog-24 \ -"${testcvs} admin -oHEAD 1/first-dir/file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -deleting revision 1\.5 -done" - - dotest keywordlog-25 \ -"${testcvs} -q co -p first-dir/file1" \ -"initial -xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.4 [0-9/]* [0-9:]* ${username} -xx First log line -xx Second log line -xx" - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -r 1 2 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - keywordname) - # Test the Name keyword. - # See the keyword test for a descriptions of some other tests that - # test keyword expansion modes. - mkdir keywordname; cd keywordname - mkdir 1; cd 1 - dotest keywordname-init-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest keywordname-init-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - echo '$'"Name$" >file1 - echo '$'"Name$" >file2 - dotest keywordname-init-3 "${testcvs} add file1 file2" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - - # See "rmadd" for a list of other tests of cvs ci -r. - dotest keywordname-init-4 "${testcvs} -q ci -r 1.3 -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.3 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.3 -done" - dotest keywordname-init-5b "cat file1" \ -'\$''Name: \$' - dotest keywordname-init-5c "cat file2" \ -'\$''Name: \$' - - dotest keywordname-init-6 "$testcvs -q up -A" - dotest keywordname-init-6b "cat file1" \ -'\$''Name: \$' - dotest keywordname-init-6c "cat file2" \ -'\$''Name: \$' - - dotest keywordname-init-7 "${testcvs} -q tag -b br" \ -"T file1 -T file2" - - echo new data >>file1 - dotest keywordname-init-8 "${testcvs} -q ci -mchange" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.4; previous revision: 1\.3 -done" - - # First check out a branch. - # - # There used to be a bug where static tags would be substituted for - # Name keywords but not branch tags. - # - # Prior to 1.11.23, there also used to be a bug where keyword - # substitutions were not performed unless the file was otherwise - # updated. When this bug was present, keywordname-update-1 would - # report a patch checksum failure and refetch file1 in client/server - # mode and no `br' would have been substituted into Name's value for - # file2, meaning keywordname-update-3 would also fail. - dotest keywordname-update-1 "$testcvs -q up -rbr" \ -'U file1 -U file2' - dotest keywordname-update-2 "cat file1" '\$''Name: br \$' - - # For the same reason keywordname-update-1 would fail above, no `br' - # would have been substituted into Name's value here prior to - # 1.11.23. - dotest keywordname-update-3 "cat file2" '\$''Name: br \$' - - # Now verify that updating to the trunk leaves no substitution for - # $Name - dotest keywordname-update-4 "${testcvs} -q tag firsttag" \ -"T file1 -T file2" - # This used to fail in the same manner as keywordname-update-1. - dotest keywordname-update-5 "$testcvs -q up -A" \ -'U file1 -U file2' - dotest keywordname-update-6 "cat file1" \ -'\$''Name: \$ -new data' - dotest keywordname-update-7 "cat file2" '\$''Name: \$' - - # This used to fail in the same manner as keywordname-update-1. - dotest keywordname-update-8 "$testcvs -q up -rfirsttag" \ -'U file1 -U file2' - dotest keywordname-update-9 "cat file1" '\$''Name: firsttag \$' - - # This used to fail in the same manner as keywordname-update-3. - dotest keywordname-update-10 "cat file2" '\$''Name: firsttag \$' - - # And reverify the trunk update when the change is actually removed. - dotest keywordname-update-11 "$testcvs -q up -A" \ -'U file1 -U file2' - dotest keywordname-update-12 "cat file1" \ -'\$''Name: \$ -new data' - dotest keywordname-update-13 "cat file2" '\$''Name: \$' - - cd ../.. - - # now verify that a fresh checkout substitutes all the $Name fields - mkdir 2; cd 2 - dotest keywordname-checkout-1 \ -"${testcvs} -q co -rfirsttag first-dir" \ -"U first-dir/file1 -U first-dir/file2" - cd first-dir - dotest keywordname-checkout-2 "cat file1" '\$'"Name: firsttag "'\$' - dotest keywordname-checkout-3 "cat file2" '\$'"Name: firsttag "'\$' - - cd ../.. - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd .. - rm -r keywordname - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - keyword2) - # Test merging on files with keywords: - # without -kk - # with -kk - # on text files - # on binary files - # Note: This test assumes that CVS has already passed the binfiles - # test sequence - # Note2: We are testing positive on binary corruption here - # we probably really DON'T want to 'cvs update -kk' a binary file... - mkdir 1; cd 1 - dotest keyword2-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest keyword2-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - echo '$''Revision$' >> file1 - echo "I" >>file1 - echo "like" >>file1 - echo "long" >>file1 - echo "files!" >>file1 - echo "" >>file1 - echo "a test line for our times" >>file1 - echo "" >>file1 - echo "They" >>file1 - echo "make" >>file1 - echo "diff" >>file1 - echo "look like it" >>file1 - echo "did a much better" >>file1 - echo "job." >>file1 - dotest keyword2-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - - ${AWK} 'BEGIN { printf "%c%c%c%sRevision: 1.1 $@%c%c", \ - 2, 10, 137, "$", 13, 10 }' \ - </dev/null | ${TR} '@' '\000' >../binfile.dat - cp ../binfile.dat . - dotest keyword2-5 "${testcvs} add -kb binfile.dat" \ -"${PROG} add: scheduling file .binfile\.dat. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - - dotest keyword2-6 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/binfile\.dat,v -done -Checking in binfile\.dat; -${CVSROOT_DIRNAME}/first-dir/binfile\.dat,v <-- binfile\.dat -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - - dotest keyword2-7 "${testcvs} -q tag -b branch" \ -"T binfile\.dat -T file1" - - sed -e 's/our/the best of and the worst of/' file1 >f; mv f file1 - dotest keyword2-8 "${testcvs} -q ci -m change" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - - dotest keyword2-9 "$testcvs -q update -r branch" \ -'U binfile\.dat -[UP] file1' - - echo "what else do we have?" >>file1 - dotest keyword2-10 "${testcvs} -q ci -m change" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - # Okay, first a conflict in file1 - should be okay with binfile.dat - dotest keyword2-11 "$testcvs -q update -A -j branch" \ -"U binfile\.dat -U file1 -RCS file: $CVSROOT_DIRNAME/first-dir/file1,v -retrieving revision 1\.1 -retrieving revision 1\.1\.2\.1 -Merging differences between 1\.1 and 1\.1\.2\.1 into file1 -rcsmerge: warning: conflicts during merge" - - dotest_fail keyword2-12 "${testcvs} diff file1" \ -"Index: file1 -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.2 -diff -r1\.2 file1 -0a1 -> <<<<<<< file1 -1a3,5 -> ======= -> \\\$""Revision: 1\.1\.2\.1 \\\$ -> >>>>>>> 1\.1\.2\.1 -14a19 -> what else do we have${QUESTION}" - - # Here's the problem... shouldn't -kk a binary file... - rm file1 - dotest keyword2-13 "${testcvs} -q update -A -kk -j branch" \ -"${PROG} update: warning: file1 was lost -U file1 -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.1 -retrieving revision 1\.1\.2\.1 -Merging differences between 1\.1 and 1\.1\.2\.1 into file1" - - # binfile won't get checked in, but it is now corrupt and could - # have been checked in if it had changed on the branch... - dotest keyword2-14 "${testcvs} -q ci -m change" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 -done" - - # "-kk" no longer corrupts binary files - dotest keyword2-15 "cmp binfile.dat ../binfile.dat" '' - - # Okay, restore everything and make CVS try and merge a binary file... - # "-kk" no longer affects binary files - dotest keyword2-16 "${testcvs} -q update -A" \ -"[UP] file1" - dotest keyword2-17 "${testcvs} -q tag -b branch2" \ -"T binfile\.dat -T file1" - dotest keyword2-18 "$testcvs -q update -r branch2" \ -'U binfile\.dat -[UP] file1' - - ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \ - </dev/null | ${TR} '@' '\000' >>binfile.dat - dotest keyword2-19 "${testcvs} -q ci -m badbadbad" \ -"Checking in binfile\.dat; -${CVSROOT_DIRNAME}/first-dir/binfile\.dat,v <-- binfile\.dat -new revision: 1\.1\.4\.1; previous revision: 1\.1 -done" - # "-kk" no longer affects binary files - - # XXXX: do not ask, why we get the "U binfile.dat" line twice - # looks like a bug! - dotest keyword2-20 "${testcvs} -q update -A -kk -j branch2" \ -"U binfile\.dat -U binfile\.dat -U file1" - - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - head) - # Testing handling of the HEAD special tag. - # There are many cases involving added and removed files - # which we don't yet try to deal with. - # TODO: We also could be paying much closer attention to - # "head of the trunk" versus "head of the default branch". - # That is what "cvs import" is doing here (but I didn't really - # fully follow through on writing the tests for that case). - mkdir imp-dir - cd imp-dir - echo 'imported contents' >file1 - # It may seem like we don't do much with file2, but do note that - # the "cvs diff" invocations do also diff file2 (and come up empty). - echo 'imported contents' >file2 - dotest_sort head-1 "${testcvs} import -m add first-dir tag1 tag2" \ -" - -N first-dir/file1 -N first-dir/file2 -No conflicts created by this import" - cd .. - rm -r imp-dir - mkdir 1 - cd 1 - dotest head-2 "${testcvs} -q co first-dir" \ -"U first-dir/file1 -U first-dir/file2" - cd first-dir - echo 'add a line on trunk' >> file1 - dotest head-3 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - dotest head-4 "${testcvs} -q tag trunktag" "T file1 -T file2" - echo 'add a line on trunk after trunktag' >> file1 - dotest head-5 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 -done" - dotest head-6 "${testcvs} -q tag -b br1" "T file1 -T file2" - dotest head-7 "$testcvs -q update -r br1" \ -'[UP] file1 -[UP] file2' - echo 'modify on branch' >>file1 - dotest head-8 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.3\.2\.1; previous revision: 1\.3 -done" - dotest head-9 "${testcvs} -q tag brtag" "T file1 -T file2" - echo 'modify on branch after brtag' >>file1 - dotest head-10 "${testcvs} -q ci -m modify" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.3\.2\.2; previous revision: 1\.3\.2\.1 -done" - # With no sticky tags, HEAD is the head of the trunk. - dotest head-trunk-setup "$testcvs -q update -A" \ -'[UP] file1 -[UP] file2' - dotest head-trunk-update "${testcvs} -q update -r HEAD -p file1" \ -"imported contents -add a line on trunk -add a line on trunk after trunktag" - # and diff thinks so too. Case (a) from the comment in - # cvs.texinfo (Common options). - dotest_fail head-trunk-diff "${testcvs} -q diff -c -r HEAD -r br1" \ -"Index: file1 -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.3 -retrieving revision 1\.3\.2\.2 -diff -c -r1\.3 -r1\.3\.2\.2 -\*\*\* file1 ${RFCDATE} 1\.3 ---- file1 ${RFCDATE} 1\.3\.2\.2 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1,3 \*\*\*\* ---- 1,5 ---- - imported contents - add a line on trunk - add a line on trunk after trunktag -${PLUS} modify on branch -${PLUS} modify on branch after brtag" - - # With a branch sticky tag, HEAD is the head of the trunk. - dotest head-br1-setup "$testcvs -q update -r br1" \ -'[UP] file1 -[UP] file2' - dotest head-br1-update "${testcvs} -q update -r HEAD -p file1" \ -"imported contents -add a line on trunk -add a line on trunk after trunktag" - # But diff thinks that HEAD is "br1". Case (b) from cvs.texinfo. - # Probably people are relying on it. - dotest head-br1-diff "${testcvs} -q diff -c -r HEAD -r br1" "" - - # With a nonbranch sticky tag on a branch, - # HEAD is the head of the trunk - dotest head-brtag-setup "$testcvs -q update -r brtag" \ -'[UP] file1 -[UP] file2' - dotest head-brtag-update "${testcvs} -q update -r HEAD -p file1" \ -"imported contents -add a line on trunk -add a line on trunk after trunktag" - - # CVS 1.9 and older thought that HEAD is "brtag" (this was - # noted as "strange, maybe accidental"). But "br1" makes a - # whole lot more sense. - dotest head-brtag-diff "${testcvs} -q diff -c -r HEAD -r br1" "" - - # With a nonbranch sticky tag on the trunk, HEAD is the head - # of the trunk, I think. - dotest head-trunktag-setup "$testcvs -q update -r trunktag" \ -'[UP] file1 -[UP] file2' - dotest head-trunktag-check "cat file1" "imported contents -add a line on trunk" - dotest head-trunktag-update "${testcvs} -q update -r HEAD -p file1" \ -"imported contents -add a line on trunk -add a line on trunk after trunktag" - # Like head-brtag-diff, there is a non-branch sticky tag. - dotest_fail head-trunktag-diff \ - "${testcvs} -q diff -c -r HEAD -r br1" \ -"Index: file1 -=================================================================== -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -retrieving revision 1\.3 -retrieving revision 1\.3\.2\.2 -diff -c -r1\.3 -r1\.3\.2\.2 -\*\*\* file1 ${RFCDATE} 1\.3 ---- file1 ${RFCDATE} 1\.3\.2\.2 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\* 1,3 \*\*\*\* ---- 1,5 ---- - imported contents - add a line on trunk - add a line on trunk after trunktag -${PLUS} modify on branch -${PLUS} modify on branch after brtag" - - # Also might test what happens if we setup with update -r - # HEAD. In general, if sticky tags matter, does the - # behavior of "update -r <foo>" (without -p) depend on the - # sticky tags before or after the update? - - # Note that we are testing both the case where this deletes - # a revision (file1) and the case where it does not (file2) - dotest_fail head-o0a "${testcvs} admin -o ::br1" \ -"${PROG} admin: Administrating \. -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -${PROG} admin: cannot remove revision 1\.3\.2\.1 because it has tags -${PROG} admin: RCS file for .file1. not modified\. -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - dotest head-o0b "${testcvs} tag -d brtag" \ -"${PROG} tag: Untagging \. -D file1 -D file2" - dotest head-o1 "${testcvs} admin -o ::br1" \ -"${PROG} admin: Administrating \. -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -deleting revision 1\.3\.2\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - tagdate) - # Test combining -r and -D. - # - # Note that this is not a complete test. It relies on the fact - # that update, checkout and export have a LOT of shared code. - # Notice: - # 1) checkout is never tested at all with -r -D - # 2) update never uses an argument to '-D' besides 'now' - # (this test does not provide enough data to prove - # that 'cvs update' with both a '-r' and a '-D' - # specified does not ignore '-D': a 'cvs up - # -r<branch> -Dnow' and a 'cvs up -r<branch>' - # should specify the same file revision). - # 3) export uses '-r<branch> -D<when there was a different - # revision>', hopefully completing this behavior test - # for checkout and update as well. - # - mkdir 1; cd 1 - save_TZ=$TZ - TZ=UTC; export TZ - dotest tagdate-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest tagdate-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - echo trunk-1 >file1 - dotest tagdate-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest tagdate-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - date_T1=`getrlogdate -r1.1 first-dir/file1` - - dotest tagdate-5 "${testcvs} -q tag -b br1" "T file1" - dotest tagdate-6 "${testcvs} -q tag -b br2" "T file1" - echo trunk-2 >file1 - dotest tagdate-7 "${testcvs} -q ci -m modify-on-trunk" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done" - date_T2=`getrlogdate -r1.2 first-dir/file1` - - # We are testing -r -D where br1 is a (magic) branch without - # any revisions. First the case where br2 doesn't have any - # revisions either: - dotest tagdate-8 "${testcvs} -q update -p -r br1 -D now" "trunk-1" - dotest tagdate-9 "${testcvs} -q update -r br2" "[UP] file1" - echo br2-1 >file1 - dotest tagdate-10 "${testcvs} -q ci -m modify-on-br2" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.4\.1; previous revision: 1\.1 -done" - date_T3=`getrlogdate -r1.1.4.1 first-dir/file1` - - # Then the case where br2 does have revisions: - dotest tagdate-11 "${testcvs} -q update -p -r br1 -D now" "trunk-1" - - # For some reason, doing this on a branch seems to be relevant. - dotest_fail tagdate-12 "${testcvs} -q update -j:yesterday" \ -"${PROG} \[update aborted\]: argument to join may not contain a date specifier without a tag" - # And check export - - echo br2-2 >file1 - dotest tagdate-13 "${testcvs} -q ci -m modify-2-on-br2" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.4\.2; previous revision: 1\.1\.4\.1 -done" - date_T4=`getrlogdate -r1.1.4.2 first-dir/file1` - - cd ../.. - mkdir 2; cd 2 - dotest tagdate-14 "${testcvs} -q export -r br2 -D'$date_T3' first-dir" \ -"[UP] first-dir/file1" - dotest tagdate-15 "cat first-dir/file1" "br2-1" - - # Now for annotate - cd ../1/first-dir - dotest tagdate-16 "${testcvs} annotate -rbr2 -D'$date_T3'" \ -" -Annotations for file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1\.4\.1 ($username8 *[0-9a-zA-Z-]*): br2-1" - - dotest tagdate-17 "${testcvs} annotate -rbr2 -Dnow" \ -" -Annotations for file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1\.4\.2 ($username8 *[0-9a-zA-Z-]*): br2-2" - - # Now check to see what happens when we add files to br2 and trunk - echo br2-1 > file3 - dotest tagdate-18 "${testcvs} add file3" \ -"${PROG} add: scheduling file \`file3' for addition on branch \`br2' -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest tagdate-19 "${testcvs} -q ci -m add file3" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v -done -Checking in file3; -${CVSROOT_DIRNAME}/first-dir/Attic/file3,v <-- file3 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - date_T5=`getrlogdate -r1.1 first-dir/file3` - date_T6=`getrlogdate -r1.1.2.1 first-dir/file3` - - cd ../.. - mkdir 3; cd 3 - dotest tagdate-20 "${testcvs} -Q co first-dir" '' - cd first-dir - echo trunk-1 > file2 - dotest tagdate-21 "${testcvs} add file2" \ -"${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest tagdate-22 "${testcvs} -q ci -m add file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - date_T7=`getrlogdate -r1.1 first-dir/file2` - echo "trunk-2" >file2 - dotest tagdate-23 "${testcvs} -q ci -m update file2" \ -"Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.2; previous revision: 1\.1 -done" - date_T8=`getrlogdate -r1.2 first-dir/file2` - - cd ../../1/first-dir - echo br2-1 > file2 - dotest tagdate-24 "${testcvs} add file2" \ -"${PROG} add: scheduling file \`file2' for addition on branch \`br2' -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest tagdate-25 "${testcvs} -q ci -m add file2" \ -"Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.2\.2\.2; previous revision: 1\.2\.2\.1 -done" - date_T9=`getrlogdate -r1.2.2.2 first-dir/file2` - cd ../.. - - # Time Rev Branch Comments - # T0 trunk first-dir created - # T1 1.1 trunk first-dir/file1 committed "trunk-1" - # br1 branch created - # br2 branch created - # T2 1.2 trunk first-dir/file1 committed "trunk-2" - # T3 1.1.4.1 br2 first-dir/file1 committed "br2-1" - # +60s - # T4 1.1.4.2 br2 first-dir/file1 committed "br2-2" - # T5 1.1 trunk first-dir/file3 dead - # T6 1.1.2.1 br2 first-dir/file3 committed "br2-1" - # T7 1.1 trunk first-dir/file2 committed "trunk-1" - # T8 1.2 trunk first-dir/file2 committed "trunk-2" - # T8 1.2.2.1 br2 first-dir/file2 dead - # T9 1.2.2.2 br2 first-dir/file2 committed "br2-1" - # - - mkdir 4; cd 4 - (echo Dates for tagdate-26-* are:;\ - echo " date_T1='$date_T1'";\ - echo " date_T2='$date_T2'";\ - echo " date_T3='$date_T3'";\ - echo " date_T4='$date_T4'";\ - echo " date_T5='$date_T5'";\ - echo " date_T6='$date_T6'";\ - echo " date_T7='$date_T7'";\ - echo " date_T8='$date_T8'";\ - echo " date_T9='$date_T9'") >>$LOGFILE - dotest tagdate-26-trunk-t1 \ -"${testcvs} co -D'$date_T1' -d first-dir-trunk-t1 first-dir" \ -"${PROG} checkout: Updating first-dir-trunk-t1 -U first-dir-trunk-t1/file1" - dotest tagdate-26-br2-t1 \ -"${testcvs} co -r br2 -D'$date_T1' -d first-dir-br2-t1 first-dir" \ -"${PROG} checkout: Updating first-dir-br2-t1 -U first-dir-br2-t1/file1" - dotest tagdate-26-trunk-t2 \ -"${testcvs} co -D'$date_T2' -d first-dir-trunk-t2 first-dir" \ -"${PROG} checkout: Updating first-dir-trunk-t2 -U first-dir-trunk-t2/file1" - dotest tagdate-26-br2-t2 \ -"${testcvs} co -r br2 -D'$date_T2' -d first-dir-br2-t2 first-dir" \ -"${PROG} checkout: Updating first-dir-br2-t2 -U first-dir-br2-t2/file1" - dotest tagdate-26-br2-t3 \ -"${testcvs} co -r br2 -D'$date_T3' -d first-dir-br2-t3 first-dir" \ -"${PROG} checkout: Updating first-dir-br2-t3 -U first-dir-br2-t3/file1" - dotest tagdate-26-br2-t4 \ -"${testcvs} co -r br2 -D'$date_T4' -d first-dir-br2-t4 first-dir" \ -"${PROG} checkout: Updating first-dir-br2-t4 -U first-dir-br2-t4/file1" - dotest tagdate-26-br2-t6 \ -"${testcvs} co -r br2 -D'$date_T6' -d first-dir-br2-t6 first-dir" \ -"${PROG} checkout: Updating first-dir-br2-t6 -U first-dir-br2-t6/file1 -U first-dir-br2-t6/file3" - dotest tagdate-26-trunk-t7 \ -"${testcvs} co -D'$date_T7' -d first-dir-trunk-t7 first-dir" \ -"${PROG} checkout: Updating first-dir-trunk-t7 -U first-dir-trunk-t7/file1 -U first-dir-trunk-t7/file2" - dotest tagdate-26-br2-t7 \ -"${testcvs} co -r br2 -D'$date_T7' -d first-dir-br2-t7 first-dir" \ -"${PROG} checkout: Updating first-dir-br2-t7 -U first-dir-br2-t7/file1 -U first-dir-br2-t7/file3" - dotest tagdate-26-trunk-t8 \ -"${testcvs} co -D'$date_T8' -d first-dir-trunk-t8 first-dir" \ -"${PROG} checkout: Updating first-dir-trunk-t8 -U first-dir-trunk-t8/file1 -U first-dir-trunk-t8/file2" - dotest tagdate-26-br2-t8 \ -"${testcvs} co -r br2 -D'$date_T8' -d first-dir-br2-t8 first-dir" \ -"${PROG} checkout: Updating first-dir-br2-t8 -U first-dir-br2-t8/file1 -U first-dir-br2-t8/file3" - dotest tagdate-26-br2-t9 \ -"${testcvs} co -r br2 -D'$date_T9' -d first-dir-br2-t9 first-dir" \ -"${PROG} checkout: Updating first-dir-br2-t9 -U first-dir-br2-t9/file1 -U first-dir-br2-t9/file2 -U first-dir-br2-t9/file3" - dotest tagdate-27-trunk-t1 \ -"${testcvs} status first-dir-trunk-t1" \ -"${PROG} status: Examining first-dir-trunk-t1 -=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1[^.]* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: (none) - Sticky Date: [0-9.]* - Sticky Options: (none)" - dotest tagdate-27-br2-t1 \ -"${testcvs} status first-dir-br2-t1" \ -"${PROG} status: Examining first-dir-br2-t1 -=================================================================== -File: file1 Status: Needs Patch - - Working revision: 1\.1[^.]* - Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: br2 (branch: 1\.1\.4) - Sticky Date: (none) - Sticky Options: (none)" - dotest tagdate-27-trunk-t2 \ -"${testcvs} status first-dir-trunk-t2" \ -"${PROG} status: Examining first-dir-trunk-t2 -=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.2[^.]* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: (none) - Sticky Date: [0-9.]* - Sticky Options: (none)" - dotest tagdate-27-br2-t2 \ -"${testcvs} status first-dir-br2-t2" \ -"${PROG} status: Examining first-dir-br2-t2 -=================================================================== -File: file1 Status: Needs Patch - - Working revision: 1\.1[^.]* - Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: br2 (branch: 1\.1\.4) - Sticky Date: (none) - Sticky Options: (none)" - dotest tagdate-27-br2-t3 \ -"${testcvs} status first-dir-br2-t3" \ -"${PROG} status: Examining first-dir-br2-t3 -=================================================================== -File: file1 Status: Needs Patch - - Working revision: 1\.1\.4\.1[^.]* - Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: br2 (branch: 1\.1\.4) - Sticky Date: (none) - Sticky Options: (none)" - dotest tagdate-27-br2-t4 \ -"${testcvs} status first-dir-br2-t4" \ -"${PROG} status: Examining first-dir-br2-t4 -=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1\.4\.2[^.]* - Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: br2 (branch: 1\.1\.4) - Sticky Date: (none) - Sticky Options: (none)" - dotest tagdate-27-br2-t6 \ -"${testcvs} status first-dir-br2-t6" \ -"${PROG} status: Examining first-dir-br2-t6 -=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1\.4\.2[^.]* - Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: br2 (branch: 1\.1\.4) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file3 Status: Up-to-date - - Working revision: 1\.1\.2\.1[^.]* - Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v - Sticky Tag: br2 (branch: 1\.1\.2) - Sticky Date: (none) - Sticky Options: (none)" - dotest tagdate-27-trunk-t7 \ -"${testcvs} status first-dir-trunk-t7" \ -"${PROG} status: Examining first-dir-trunk-t7 -=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.2[^.]* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: (none) - Sticky Date: [0-9.]* - Sticky Options: (none) - -=================================================================== -File: file2 Status: Up-to-date - - Working revision: 1\.1[^.]* - Repository revision: 1\.1 ${CVSROOT_DIRNAME}/first-dir/file2,v - Sticky Tag: (none) - Sticky Date: [0-9.]* - Sticky Options: (none)" - dotest tagdate-27-br2-t7 \ -"${testcvs} status first-dir-br2-t7" \ -"${PROG} status: Examining first-dir-br2-t7 -=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1\.4\.2[^.]* - Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: br2 (branch: 1\.1\.4) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file3 Status: Up-to-date - - Working revision: 1\.1\.2\.1[^.]* - Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v - Sticky Tag: br2 (branch: 1\.1\.2) - Sticky Date: (none) - Sticky Options: (none)" - dotest tagdate-27-trunk-t8 \ -"${testcvs} status first-dir-trunk-t8" \ -"${PROG} status: Examining first-dir-trunk-t8 -=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.2[^.]* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: (none) - Sticky Date: [0-9.]* - Sticky Options: (none) - -=================================================================== -File: file2 Status: Up-to-date - - Working revision: 1\.2[^.]* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/file2,v - Sticky Tag: (none) - Sticky Date: [0-9.]* - Sticky Options: (none)" - dotest tagdate-27-br2-t8 \ -"${testcvs} status first-dir-br2-t8" \ -"${PROG} status: Examining first-dir-br2-t8 -=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1\.4\.2[^.]* - Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: br2 (branch: 1\.1\.4) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file3 Status: Up-to-date - - Working revision: 1\.1\.2\.1[^.]* - Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v - Sticky Tag: br2 (branch: 1\.1\.2) - Sticky Date: (none) - Sticky Options: (none)" - dotest tagdate-27-br2-t9 \ -"${testcvs} status first-dir-br2-t9" \ -"${PROG} status: Examining first-dir-br2-t9 -=================================================================== -File: file1 Status: Up-to-date - - Working revision: 1\.1\.4\.2[^.]* - Repository revision: 1\.1\.4\.2 ${CVSROOT_DIRNAME}/first-dir/file1,v - Sticky Tag: br2 (branch: 1\.1\.4) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file2 Status: Up-to-date - - Working revision: 1\.2\.2\.2[^.]* - Repository revision: 1\.2\.2\.2 ${CVSROOT_DIRNAME}/first-dir/file2,v - Sticky Tag: br2 (branch: 1\.2\.2) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file3 Status: Up-to-date - - Working revision: 1\.1\.2\.1[^.]* - Repository revision: 1\.1\.2\.1 ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v - Sticky Tag: br2 (branch: 1\.1\.2) - Sticky Date: (none) - Sticky Options: (none)" - - # Now check the contents of the files - dotest tagdate-28-trunk-t1 'cat first-dir-trunk-t1/file1' 'trunk-1' - dotest tagdate-28-br2-t1 'cat first-dir-br2-t1/file1' 'trunk-1' - dotest tagdate-28-trunk-t2 'cat first-dir-trunk-t2/file1' 'trunk-2' - dotest tagdate-28-br2-t2 'cat first-dir-br2-t2/file1' 'trunk-1' - dotest tagdate-28-br2-t3 'cat first-dir-br2-t3/file1' 'br2-1' - dotest tagdate-28-br2-t4 'cat first-dir-br2-t4/file1' 'br2-2' - dotest tagdate-28-br2-t6a 'cat first-dir-br2-t6/file1' "br2-2" - dotest tagdate-28-br2-t6b 'cat first-dir-br2-t6/file3' "br2-1" - dotest tagdate-28-trunk-t7a 'cat first-dir-trunk-t7/file1' "trunk-2" - dotest tagdate-28-trunk-t7b 'cat first-dir-trunk-t7/file2' "trunk-1" - dotest tagdate-28-br2-t7a 'cat first-dir-br2-t7/file1' "br2-2" - dotest tagdate-28-br2-t7b 'cat first-dir-br2-t7/file3' "br2-1" - dotest tagdate-28-trunk-t8a 'cat first-dir-trunk-t8/file1' "trunk-2" - dotest tagdate-28-trunk-t8b 'cat first-dir-trunk-t8/file2' "trunk-2" - dotest tagdate-28-br2-t8a 'cat first-dir-br2-t8/file1' "br2-2" - dotest tagdate-28-br2-t8c 'cat first-dir-br2-t8/file3' "br2-1" - dotest tagdate-28-br2-t9a 'cat first-dir-br2-t9/file1' "br2-2" - dotest tagdate-28-br2-t9b 'cat first-dir-br2-t9/file2' "br2-1" - dotest tagdate-28-br2-t9c 'cat first-dir-br2-t9/file3' "br2-1" - cd .. - - unset date_T1 date_T2 date_T3 date_T4 date_T5 - unset date_T6 date_T7 date_T8 date_T9 - TZ=$save_TZ - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -r 1 2 3 4 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - multibranch2) - # Commit the first delta on branch A when there is an older - # branch, B, that already has a delta. A and B come from the - # same branch point. Then verify that branches A and B are - # in the right order. - mkdir 1; cd 1 - dotest multibranch2-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest multibranch2-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - echo trunk-1 >file1 - echo trunk-1 >file2 - dotest multibranch2-3 "${testcvs} add file1 file2" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest multibranch2-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - dotest multibranch2-5 "${testcvs} -q tag -b A" "T file1 -T file2" - dotest multibranch2-6 "${testcvs} -q tag -b B" "T file1 -T file2" - - dotest multibranch2-7 "$testcvs -q update -r B" \ -'[UP] file1 -[UP] file2' - echo branch-B >file1 - echo branch-B >file2 - dotest multibranch2-8 "${testcvs} -q ci -m modify-on-B" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.4\.1; previous revision: 1\.1 -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.1\.4\.1; previous revision: 1\.1 -done" - - dotest multibranch2-9 "${testcvs} -q update -r A" '[UP] file1 -[UP] file2' - echo branch-A >file1 - # When using cvs-1.9.20, this commit gets a failed assertion in rcs.c. - dotest multibranch2-10 "${testcvs} -q ci -m modify-on-A" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - - dotest multibranch2-11 "${testcvs} -q log file1" \ -" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - B: 1\.1\.0\.4 - A: 1\.1\.0\.2 -keyword substitution: kv -total revisions: 3; selected revisions: 3 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -branches: 1\.1\.2; 1\.1\.4; -add ----------------------------- -revision 1\.1\.4\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; lines: ${PLUS}1 -1 -modify-on-B ----------------------------- -revision 1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; lines: ${PLUS}1 -1 -modify-on-A -=============================================================================" - - # This one is more concise. - dotest multibranch2-12 "${testcvs} -q log -r1.1 file1" \ -" -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - B: 1\.1\.0\.4 - A: 1\.1\.0\.2 -keyword substitution: kv -total revisions: 3; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -branches: 1\.1\.2; 1\.1\.4; -add -=============================================================================" - - # OK, try very much the same thing except we run update -j to - # bring the changes from B to A. Probably tests many of the - # same code paths but might as well keep it separate, I guess. - - dotest multibranch2-13 "${testcvs} -q update -r B" "[UP] file1 -[UP] file2" - dotest multibranch2-14 "${testcvs} -q update -r A -j B file2" \ -"[UP] file2 -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -retrieving revision 1.1 -retrieving revision 1.1.4.1 -Merging differences between 1.1 and 1.1.4.1 into file2" - dotest multibranch2-15 "${testcvs} -q ci -m commit-on-A file2" \ -"Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - tag8k) - # In cvs-1.9.27, there is a bug that can cause an abort. - # It happens when you commit a change to a ,v file that has - # just the right amount of tag/branch info to align one of the - # semicolons in the branch info to be on a 8k-byte boundary. - # The result: rcsbuf_getkey got an abort. This failure doesn't - # corrupt the ,v file -- that would be really serious. But it - # does leave stale write locks that have to be removed manually. - - mkdir 1 - cd 1 - - module=x - - : > junk - dotest tag8k-1 "$testcvs -Q import -m . $module X Y" '' - dotest tag8k-2 "$testcvs -Q co $module" '' - cd $module - - file=m - : > $file - dotest tag8k-3 "$testcvs add $file" \ -"${PROG} add: scheduling file .$file. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest tag8k-4 "$testcvs -Q ci -m . $file" \ -"RCS file: ${CVSROOT_DIRNAME}/$module/$file,v -done -Checking in $file; -${CVSROOT_DIRNAME}/$module/$file,v <-- $file -initial revision: 1\.1 -done" - - # It seems there have to be at least two versions. - echo a > $file - dotest tag8k-5 "$testcvs -Q ci -m . $file" \ -"Checking in $file; -${CVSROOT_DIRNAME}/$module/$file,v <-- $file -new revision: 1\.2; previous revision: 1\.1 -done" - - # Add just under 8K worth of tags. - t=TAG--------------------------------------------------------------------- - t=$t$t - t=$t$t$t$t$t - # Now $t is 720 bytes long. - - # Apply some tags with that long prefix. - dotest tag8k-6 "$testcvs -Q tag $t-0 $file" '' - dotest tag8k-7 "$testcvs -Q tag $t-1 $file" '' - dotest tag8k-8 "$testcvs -Q tag $t-2 $file" '' - dotest tag8k-9 "$testcvs -Q tag $t-3 $file" '' - dotest tag8k-10 "$testcvs -Q tag $t-4 $file" '' - dotest tag8k-11 "$testcvs -Q tag $t-5 $file" '' - dotest tag8k-12 "$testcvs -Q tag $t-6 $file" '' - dotest tag8k-13 "$testcvs -Q tag $t-7 $file" '' - dotest tag8k-14 "$testcvs -Q tag $t-8 $file" '' - dotest tag8k-15 "$testcvs -Q tag $t-9 $file" '' - dotest tag8k-16 "$testcvs -Q tag $t-a $file" '' - - # Extract the author value. - name=`sed -n 's/.*; author \([^;]*\);.*/\1/p' ${CVSROOT_DIRNAME}/$module/$file,v|sed 1q` - - # Form a suffix string of length (16 - length($name)). - # CAREFUL: this will lose if $name is longer than 16. - sed_pattern=`echo $name|sed s/././g` - suffix=`echo 1234567890123456|sed s/$sed_pattern//` - - # Add a final tag with length chosen so that it will push the - # offset of the `;' in the 2nd occurrence of `;\tauthor' in the - # ,v file to exactly 8192. - dotest tag8k-17 "$testcvs -Q tag "x8bytes-$suffix" $file" '' - - # This commit would fail with 1.9.27. - echo a >> $file - dotest tag8k-18 "$testcvs -Q ci -m . $file" \ -"Checking in $file; -${CVSROOT_DIRNAME}/$module/$file,v <-- $file -new revision: 1\.3; previous revision: 1\.2 -done" - cd ../.. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/$module - ;; - - - admin) - # More "cvs admin" tests. - # The basicb-21 test tests rejecting an illegal option. - # For -l and -u, see "reserved" and "keyword" tests. - # "binfiles" test has a test of "cvs admin -k". - # "log2" test has tests of -t and -q options to cvs admin. - # "rcs" tests -b option also. - # For -o, see: - # admin-22-o1 through admin-23 (various cases not involving ::) - # binfiles2-o* (:rev, rev on trunk; rev:, deleting entire branch) - # basicb-o* (attempt to delete all revisions) - # basica-o1 through basica-o3 (basic :: usage) - # head-o1 (::branch, where this deletes a revision or is noop) - # branches-o1 (::branch, similar, with different branch topology) - # log-o1 (1.3.2.1::) - # binfiles-o1 (1.3:: and ::1.3; binary files) - # binfiles3-9 (binary files) - # Also could be testing: - # 1.3.2.6::1.3.2.8 - # 1.3.2.6::1.3.2 - # 1.3.2.1::1.3.2.6 - # 1.3::1.3.2.6 (error? or synonym for ::1.3.2.6?) - # -n: admin, tagf tests. - - mkdir 1; cd 1 - dotest admin-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest admin-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - - dotest_fail admin-3 "${testcvs} -q admin -i file1" \ -"${PROG} admin: the -i option to admin is not supported -${PROG} admin: run add or import to create an RCS file -${PROG} \[admin aborted\]: specify ${PROG} -H admin for usage information" - dotest_fail admin-4 "${testcvs} -q log file1" \ -"${PROG} log: nothing known about file1" - dotest_fail admin-4a "${testcvs} -q admin file1" \ -"${PROG} admin: nothing known about file1" - - # Set up some files, file2 a plain one and file1 with a revision - # on a branch. - touch file1 file2 - dotest admin-5 "${testcvs} add file1 file2" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest admin-6 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - dotest admin-7 "${testcvs} -q tag -b br" "T file1 -T file2" - dotest admin-8 "$testcvs -q update -r br" \ -'U file1 -U file2' - echo 'add a line on the branch' >> file1 - echo 'add a file on the branch' >> file3 - dotest admin-9a "${testcvs} -q add file3" \ -"${PROG} add: use .${PROG} commit. to add this file permanently" - dotest admin-9b "${testcvs} -q ci -m modify-on-branch" \ -"Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v -done -Checking in file3; -${CVSROOT_DIRNAME}/first-dir/Attic/file3,v <-- file3 -new revision: 1\.1\.2\.1; previous revision: 1\.1 -done" - dotest admin-10 "$testcvs -q update -A" \ -"U file1 -U file2 -$PROG update: file3 is no longer in the repository" - - # Check that we can administer files in the repository that - # aren't in the working directory. - dotest admin-10-1 "${testcvs} admin ." \ -"${PROG} admin: Administrating . -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - dotest admin-10-2 "${testcvs} -q admin file3" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v -done" - - # Try to recurse with a numeric revision arg. - # If we wanted to comprehensive about this, we would also test - # this for -l, -u, and all the different -o syntaxes. - dotest_fail admin-10a "${testcvs} -q admin -b1.1.2" \ -"${PROG} [a-z]*: while processing more than one file: -${PROG} \[[a-z]* aborted\]: attempt to specify a numeric revision" - dotest_fail admin-10b "${testcvs} -q admin -m1.1:bogus file1 file2" \ -"${PROG} [a-z]*: while processing more than one file: -${PROG} \[[a-z]* aborted\]: attempt to specify a numeric revision" - - # try a bad symbolic revision - dotest_fail admin-10c "${testcvs} -q admin -bBOGUS" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/file1,v: Symbolic name BOGUS is undefined. -${PROG} admin: RCS file for .file1. not modified\. -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/file2,v: Symbolic name BOGUS is undefined. -${PROG} admin: RCS file for .file2. not modified\." - - # Note that -s option applies to the new default branch, not - # the old one. - # Also note that the implementation of -a via "rcs" requires - # no space between -a and the argument. However, we expect - # to change that once CVS parses options. - dotest admin-11 "${testcvs} -q admin -afoo,bar -abaz \ --b1.1.2 -cxx -U -sfoo file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done" - dotest admin-11a "${testcvs} log -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: 1\.1\.2 -locks: -access list: - foo - bar - baz -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -branches: 1\.1\.2; -add ----------------------------- -revision 1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: foo; lines: ${PLUS}1 -0 -modify-on-branch -=============================================================================" - dotest admin-12 "${testcvs} -q admin -bbr file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done" - dotest admin-12a "${testcvs} log -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: 1\.1\.2 -locks: -access list: - foo - bar - baz -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -branches: 1\.1\.2; -add ----------------------------- -revision 1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: foo; lines: ${PLUS}1 -0 -modify-on-branch -=============================================================================" - - # "cvs log" doesn't print the comment leader. RCS 5.7 will print - # the comment leader only if one specifies "-V4" to rlog. So it - # seems like the only way to test it is by looking at the RCS file - # directly. This also serves as a test of exporting RCS files - # (analogous to the import tests in "rcs"). - # Rather than try to write a rigorous check for whether the - # file CVS exports is legal, we just write a simpler - # test for what CVS actually exports, and figure we can revise - # the check as needed (within the confines of the RCS5 format as - # documented in RCSFILES). - # Note that we must accept either 2 or 4 digit year. - dotest admin-13 "cat ${CVSROOT_DIRNAME}/first-dir/file1,v" \ -"head 1\.1; -branch 1\.1\.2; -access - foo - bar - baz; -symbols - br:1\.1\.0\.2; -locks; -comment @xx@; - - -1\.1 -date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; -branches - 1\.1\.2\.1; -next ; - -1\.1\.2\.1 -date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state foo; -branches; -next ; - - -desc -@@ - - -1\.1 -log -@add -@ -text -@@ - - -1\.1\.2\.1 -log -@modify-on-branch -@ -text -@a0 1 -add a line on the branch -@" - dotest_fail admin-14-1 "${testcvs} -q admin \ --m1.1.1.1:changed-bogus-log-message file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -cvs admin: ${CVSROOT_DIRNAME}/first-dir/file2,v: no such revision 1\.1\.1\.1 -cvs admin: RCS file for .file2. not modified." - dotest admin-14-2 "${testcvs} -q log file2" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -Working file: file2 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - br: 1\.1\.0\.2 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -add -=============================================================================" - - dotest admin-14-3 "${testcvs} -q admin -aauth3 -aauth2,foo \ --soneone:1.1 -m1.1:changed-log-message -ntagone: file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - dotest admin-15 "${testcvs} -q log file2" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -Working file: file2 -head: 1\.1 -branch: -locks: strict -access list: - auth3 - auth2 - foo -symbolic names: - tagone: 1\.1 - br: 1\.1\.0\.2 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: oneone; -changed-log-message -=============================================================================" - - dotest admin-16 "${testcvs} -q admin \ --A${CVSROOT_DIRNAME}/first-dir/file2,v -b -L -Nbr:1.1 file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done" - dotest admin-17 "${testcvs} -q log file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: - foo - bar - baz - auth3 - auth2 -symbolic names: - br: 1\.1 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -branches: 1\.1\.2; -add ----------------------------- -revision 1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: foo; lines: ${PLUS}1 -0 -modify-on-branch -=============================================================================" - - dotest_fail admin-18 "${testcvs} -q admin -nbr:1.1.2 file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/file1,v: symbolic name br already bound to 1\.1 -${PROG} admin: RCS file for .file1. not modified\." - dotest admin-19 "${testcvs} -q admin -ebaz -ebar,auth3 -nbr file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done" - dotest admin-20 "${testcvs} -q log file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: - foo - auth2 -symbolic names: -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -branches: 1\.1\.2; -add ----------------------------- -revision 1.1.2.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: foo; lines: ${PLUS}1 -0 -modify-on-branch -=============================================================================" - - # OK, this is starting to get ridiculous, in terms of - # testing a feature (access lists) which doesn't do anything - # useful, but what about nonexistent files and - # relative pathnames in admin -A? - dotest_fail admin-19a-nonexist \ -"${testcvs} -q admin -A${TESTDIR}/foo/bar file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -${PROG} admin: Couldn't open rcs file .${TESTDIR}/foo/bar.: No such file or directory -${PROG} \[admin aborted\]: cannot continue" - - # In the remote case, we are cd'd off into the temp directory - # and so these tests give "No such file or directory" errors. - if $remote; then :; else - dotest admin-19a-admin "${testcvs} -q admin -A../../${CVSROOTDIR}/first-dir/file2,v file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done" - dotest admin-19a-log "${testcvs} -q log -h -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: - foo - auth2 - auth3 -keyword substitution: kv -total revisions: 2 -=============================================================================" - 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: ${CVSROOT_DIRNAME}/first-dir/file1,v -done" - dotest admin-19a-3 "${testcvs} -q log -h -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 2 -=============================================================================" - - # Put the access list back, to avoid special cases later. - dotest admin-19a-4 "${testcvs} -q admin -afoo,auth2 file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done" - - # Add another revision to file2, so we can delete one. - echo 'add a line' >> file2 - dotest admin-21 "${testcvs} -q ci -m modify file2" \ -"Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.2; previous revision: 1\.1 -done" - dotest admin-22 "${testcvs} -q admin -o1.1 file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -deleting revision 1\.1 -done" - # Test admin -o. More variants that we could be testing: - # * REV: [on branch] - # * REV1:REV2 [deleting whole branch] - # * high branch numbers (e.g. 1.2.2.3.2.3) - # ... and probably others. See RCS_delete_revs for ideas. - - echo first rev > aaa - dotest admin-22-o1 "${testcvs} add aaa" \ -"${PROG} add: scheduling file .aaa. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest admin-22-o2 "${testcvs} -q ci -m first aaa" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -done -Checking in aaa; -${CVSROOT_DIRNAME}/first-dir/aaa,v <-- aaa -initial revision: 1\.1 -done" - echo second rev >> aaa - dotest admin-22-o3 "${testcvs} -q ci -m second aaa" \ -"Checking in aaa; -${CVSROOT_DIRNAME}/first-dir/aaa,v <-- aaa -new revision: 1\.2; previous revision: 1\.1 -done" - echo third rev >> aaa - dotest admin-22-o4 "${testcvs} -q ci -m third aaa" \ -"Checking in aaa; -${CVSROOT_DIRNAME}/first-dir/aaa,v <-- aaa -new revision: 1\.3; previous revision: 1\.2 -done" - echo fourth rev >> aaa - dotest admin-22-o5 "${testcvs} -q ci -m fourth aaa" \ -"Checking in aaa; -${CVSROOT_DIRNAME}/first-dir/aaa,v <-- aaa -new revision: 1\.4; previous revision: 1\.3 -done" - echo fifth rev >>aaa - dotest admin-22-o6 "${testcvs} -q ci -m fifth aaa" \ -"Checking in aaa; -${CVSROOT_DIRNAME}/first-dir/aaa,v <-- aaa -new revision: 1\.5; previous revision: 1\.4 -done" - echo sixth rev >> aaa - dotest admin-22-o7 "${testcvs} -q ci -m sixth aaa" \ -"Checking in aaa; -${CVSROOT_DIRNAME}/first-dir/aaa,v <-- aaa -new revision: 1\.6; previous revision: 1\.5 -done" - dotest admin-22-o8 "${testcvs} admin -l1.6 aaa" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -1\.6 locked -done" - dotest admin-22-o9 "${testcvs} log -r1.6 aaa" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -Working file: aaa -head: 1\.6 -branch: -locks: strict - ${username}: 1\.6 -access list: -symbolic names: -keyword substitution: kv -total revisions: 6; selected revisions: 1 -description: ----------------------------- -revision 1\.6 locked by: ${username}; -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -sixth -=============================================================================" - dotest_fail admin-22-o10 "${testcvs} admin -o1.5: aaa" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/aaa,v: can't remove locked revision 1\.6 -${PROG} admin: RCS file for .aaa. not modified\." - dotest admin-22-o11 "${testcvs} admin -u aaa" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -1\.6 unlocked -done" - dotest admin-22-o12 "${testcvs} admin -o1.5: aaa" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -deleting revision 1\.6 -deleting revision 1\.5 -done" - dotest admin-22-o13 "${testcvs} log aaa" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -Working file: aaa -head: 1\.4 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 4; selected revisions: 4 -description: ----------------------------- -revision 1\.4 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -fourth ----------------------------- -revision 1\.3 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -third ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -second ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -first -=============================================================================" - - dotest admin-22-o14 "${testcvs} tag -b -r1.3 br1 aaa" "T aaa" - dotest admin-22-o15 "${testcvs} update -rbr1 aaa" "U aaa" - echo new branch rev >> aaa - dotest admin-22-o16 "${testcvs} ci -m new-branch aaa" \ -"Checking in aaa; -${CVSROOT_DIRNAME}/first-dir/aaa,v <-- aaa -new revision: 1\.3\.2\.1; previous revision: 1\.3 -done" - dotest_fail admin-22-o17 "${testcvs} admin -o1.2:1.4 aaa" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -deleting revision 1\.4 -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/aaa,v: can't remove branch point 1\.3 -${PROG} admin: RCS file for .aaa. not modified\." - dotest admin-22-o18 "${testcvs} update -p -r1.4 aaa" \ -"=================================================================== -Checking out aaa -RCS: ${CVSROOT_DIRNAME}/first-dir/aaa,v -VERS: 1\.4 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -first rev -second rev -third rev -fourth rev" - echo second branch rev >> aaa - dotest admin-22-o19 "${testcvs} ci -m branch-two aaa" \ -"Checking in aaa; -${CVSROOT_DIRNAME}/first-dir/aaa,v <-- aaa -new revision: 1\.3\.2\.2; previous revision: 1\.3\.2\.1 -done" - echo third branch rev >> aaa - dotest admin-22-o20 "${testcvs} ci -m branch-three aaa" \ -"Checking in aaa; -${CVSROOT_DIRNAME}/first-dir/aaa,v <-- aaa -new revision: 1\.3\.2\.3; previous revision: 1\.3\.2\.2 -done" - echo fourth branch rev >> aaa - dotest admin-22-o21 "${testcvs} ci -m branch-four aaa" \ -"Checking in aaa; -${CVSROOT_DIRNAME}/first-dir/aaa,v <-- aaa -new revision: 1\.3\.2\.4; previous revision: 1\.3\.2\.3 -done" - dotest admin-22-o22 "${testcvs} admin -o:1.3.2.3 aaa" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -deleting revision 1\.3\.2\.1 -deleting revision 1\.3\.2\.2 -deleting revision 1\.3\.2\.3 -done" - dotest admin-22-o23 "${testcvs} log aaa" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -Working file: aaa -head: 1\.4 -branch: -locks: strict -access list: -symbolic names: - br1: 1\.3\.0\.2 -keyword substitution: kv -total revisions: 5; selected revisions: 5 -description: ----------------------------- -revision 1\.4 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -fourth ----------------------------- -revision 1\.3 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -branches: 1\.3\.2; -third ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -second ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -first ----------------------------- -revision 1\.3\.2\.4 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}4 -0 -branch-four -=============================================================================" - - dotest admin-22-o24 "${testcvs} -q update -p -r 1.3.2.4 aaa" \ -"first rev -second rev -third rev -new branch rev -second branch rev -third branch rev -fourth branch rev" - - # The bit here about how there is a "tagone" tag pointing to - # a nonexistent revision is documented by rcs. I dunno, I - # wonder whether the "cvs admin -o" should give a warning in - # this case. - dotest admin-23 "${testcvs} -q log file2" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -Working file: file2 -head: 1\.2 -branch: -locks: strict -access list: - auth3 - auth2 - foo -symbolic names: - tagone: 1\.1 - br: 1\.1\.0\.2 -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -modify -=============================================================================" - - dotest admin-25 "cat ${CVSROOT_DIRNAME}/first-dir/file1,v" \ -"head 1\.1; -access - foo - auth2; -symbols; -locks; strict; -comment @xx@; - - -1\.1 -date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; -branches - 1\.1\.2\.1; -next ; - -1\.1\.2\.1 -date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state foo; -branches; -next ; - - -desc -@@ - - -1\.1 -log -@add -@ -text -@@ - - -1\.1\.2\.1 -log -@modify-on-branch -@ -text -@a0 1 -add a line on the branch -@" - - # Tests of cvs admin -n. Make use of the results of - # admin-1 through admin-25. - # FIXME: We probably shouldn't make use of those results; - # this test is way too long as it is. - - # tagtwo should be a revision - # - dotest admin-26-1 "${testcvs} admin -ntagtwo:tagone file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - - # br1 should be a branch - # - dotest admin-26-2 "${testcvs} admin -nbr1:br file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - - # Attach some tags using RCS versions - # - dotest admin-26-3 "${testcvs} admin -ntagthree:1.1 file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - - dotest admin-26-4 "${testcvs} admin -nbr2:1.1.2 file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - - dotest admin-26-5 "${testcvs} admin -nbr4:1.1.0.2 file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - - # Check results so far - # - dotest admin-26-6 "${testcvs} status -v file2" \ -"=================================================================== -File: file2 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT_DIRNAME}/first-dir/file2,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - br4 (branch: 1\.1\.2) - br2 (branch: 1\.1\.2) - tagthree (revision: 1\.1) - br1 (branch: 1\.1\.2) - tagtwo (revision: 1\.1) - tagone (revision: 1\.1) - br (branch: 1\.1\.2)" - - - # Add a couple more revisions - # - echo "nuthr_line" >> file2 - dotest admin-27-1 "${testcvs} commit -m nuthr_line file2" \ -"Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.3; previous revision: 1\.2 -done" - - echo "yet_another" >> file2 - dotest admin-27-2 "${testcvs} commit -m yet_another file2" \ -"Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -new revision: 1\.4; previous revision: 1\.3 -done" - - # Fail trying to reattach existing tag with -n - # - dotest admin-27-3 "${testcvs} admin -ntagfour:1.1 file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - - dotest_fail admin-27-4 "${testcvs} admin -ntagfour:1.3 file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/file2,v: symbolic name tagfour already bound to 1\.1 -${PROG} admin: RCS file for .file2. not modified\." - - # Succeed at reattaching existing tag, using -N - # - dotest admin-27-5 "${testcvs} admin -Ntagfour:1.3 file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done" - - # Fail on some bogus operations - # Try to attach to nonexistant tag - # - dotest_fail admin-28-1 "${testcvs} admin -ntagsix:tagfive file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/file2,v: Symbolic name or revision tagfive is undefined\. -${PROG} admin: RCS file for .file2. not modified\." - - # Try a some nonexisting numeric target tags - # - dotest_fail admin-28-2 "${testcvs} admin -ntagseven:2.1 file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -${PROG} \[admin aborted\]: revision .2\.1. does not exist" - - dotest_fail admin-28-3 "${testcvs} admin -ntageight:2.1.2 file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -${PROG} \[admin aborted\]: revision .2\.1\.2. does not exist" - - # Try some invalid targets - # - dotest_fail admin-28-4 "${testcvs} admin -ntagnine:1.a.2 file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -${PROG} \[admin aborted\]: tag .1\.a\.2. must start with a letter" - - # Confirm that a missing tag is not a fatal error. - dotest admin-28-5.1 "${testcvs} -Q tag BO+GUS file1" '' - dotest_fail admin-28-5.2 "${testcvs} admin -ntagten:BO+GUS file2 file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/file2,v: Symbolic name or revision BO${PLUS}GUS is undefined\. -${PROG} admin: RCS file for .file2. not modified\. -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done" - - dotest_fail admin-28-6 "${testcvs} admin -nq.werty:tagfour file2" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -${PROG} \[admin aborted\]: tag .q\.werty. must not contain the characters ..*" - - # Verify the archive - # - dotest admin-29 "cat ${CVSROOT_DIRNAME}/first-dir/file2,v" \ -"head 1\.4; -access - auth3 - auth2 - foo; -symbols - tagfour:1\.3 - br4:1\.1\.0\.2 - br2:1\.1\.0\.2 - tagthree:1\.1 - br1:1\.1\.0\.2 - tagtwo:1\.1 - tagone:1\.1 - br:1\.1\.0\.2; -locks; strict; -comment @# @; - - -1\.4 -date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; -branches; -next 1\.3; - -1\.3 -date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; -branches; -next 1\.2; - -1\.2 -date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; -branches; -next ; - - -desc -@@ - - -1\.4 -log -@yet_another -@ -text -@add a line -nuthr_line -yet_another -@ - - -1\.3 -log -@nuthr_line -@ -text -@d3 1 -@ - - -1\.2 -log -@modify -@ -text -@d2 1 -@" - - dotest_fail admin-30 "${testcvs} admin -mbr:another-log-message \ -file2 aaa file3" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/file2,v: no such revision br: 1\.1 -${PROG} admin: RCS file for .file2. not modified. -RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/aaa,v: no such revision br -${PROG} admin: RCS file for .aaa. not modified. -RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v -done" - dotest admin-31 "${testcvs} log" \ -"${PROG} log: Logging \. - -RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v -Working file: aaa -head: 1\.4 -branch: -locks: strict -access list: -symbolic names: - br1: 1\.3\.0\.2 -keyword substitution: kv -total revisions: 5; selected revisions: 5 -description: ----------------------------- -revision 1\.4 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -fourth ----------------------------- -revision 1\.3 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -branches: 1\.3\.2; -third ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -second ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -first ----------------------------- -revision 1\.3\.2\.4 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}4 -0 -branch-four -============================================================================= - -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: - foo - auth2 -symbolic names: - tagten: 1\.1 - BO${PLUS}GUS: 1\.1 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -branches: 1\.1\.2; -add ----------------------------- -revision 1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: foo; lines: ${PLUS}1 -0 -modify-on-branch -============================================================================= - -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -Working file: file2 -head: 1\.4 -branch: -locks: strict -access list: - auth3 - auth2 - foo -symbolic names: - tagfour: 1\.3 - br4: 1\.1\.0\.2 - br2: 1\.1\.0\.2 - tagthree: 1\.1 - br1: 1\.1\.0\.2 - tagtwo: 1\.1 - tagone: 1\.1 - br: 1\.1\.0\.2 -keyword substitution: kv -total revisions: 3; selected revisions: 3 -description: ----------------------------- -revision 1\.4 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -yet_another ----------------------------- -revision 1\.3 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -nuthr_line ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -modify -============================================================================= - -RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v -Working file: file3 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: - br: 1\.1\.0\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: dead; -branches: 1\.1\.2; -file file3 was initially added on branch br\. ----------------------------- -revision 1\.1\.2\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -another-log-message -=============================================================================" - - cd ../.. - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - # clean up our after ourselves - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - reserved) - # Tests of reserved checkouts. Eventually this will test - # rcslock.pl (or equivalent) and all kinds of stuff. Right - # now it just does some very basic checks on cvs admin -u - # and cvs admin -l. - # Also should test locking on a branch (and making sure that - # locks from one branch don't get mixed up with those from - # another. Both the case where one of the branches is the - # main branch, and in which neither one is). - # See also test keyword, which tests that keywords and -kkvl - # do the right thing in the presence of locks. - - # The usual setup, directory first-dir containing file file1. - mkdir 1; cd 1 - dotest reserved-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest reserved-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch file1 - dotest reserved-3 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest reserved-4 "${testcvs} -q ci -m add" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - - dotest reserved-5 "${testcvs} -q admin -l file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -1\.1 locked -done" - dotest reserved-6 "${testcvs} log -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict - ${username}: 1\.1 -access list: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 locked by: ${username}; -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -add -=============================================================================" - - # Note that this just tests the owner of the lock giving - # it up. It doesn't test breaking a lock. - dotest reserved-7 "${testcvs} -q admin -u file1" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -1\.1 unlocked -done" - - dotest reserved-8 "${testcvs} log -N file1" " -RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -Working file: file1 -head: 1\.1 -branch: -locks: strict -access list: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -add -=============================================================================" - - # rcslock.pl tests. Of course, the point isn't to test - # rcslock.pl from the distribution but equivalent - # functionality (for example, many sites may have an old - # rcslock.pl). The functionality of this hook falls - # short of the real rcslock.pl though. - # Note that we can use rlog or look at the RCS file directly, - # but we can't use "cvs log" because "cvs commit" has a lock. - - cat >${TESTDIR}/lockme <<EOF -#!${TESTSHELL} -line=\`grep <\$1/\$2,v 'locks $anyusername:1\.[0-9];'\` -if test -z "\$line"; then - # It isn't locked - exit 0 -else - user=\`echo \$line | sed -e 's/locks \\($anyusername\\):[0-9.]*;.*/\\1/'\` - version=\`echo \$line | sed -e 's/locks $anyusername:\\([0-9.]*\\);.*/\\1/'\` - echo "\$user has file a-lock locked for version \$version" >&2 - exit 1 -fi -EOF - # Cygwin. Blaaarg. - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod +x ${TESTDIR}/lockme" - else - chmod +x ${TESTDIR}/lockme - fi - - echo stuff > a-lock - dotest reserved-9 "${testcvs} add a-lock" \ -"${PROG} add: scheduling file .a-lock. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest reserved-10 "${testcvs} -q ci -m new a-lock" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/a-lock,v -done -Checking in a-lock; -${CVSROOT_DIRNAME}/first-dir/a-lock,v <-- a-lock -initial revision: 1\.1 -done" - # FIXME: the contents of CVSROOT fluctuate a lot - # here. Maybe the expect pattern should just - # confirm that commitinfo is one of the files checked out, - # but for now we just check that CVS exited with success. - cd .. - if ${testcvs} -q co CVSROOT >>${LOGFILE} ; then - pass reserved-11 - else - fail reserved-11 - fi - cd CVSROOT - echo "DEFAULT ${TESTDIR}/lockme" >>commitinfo - dotest reserved-12 "${testcvs} -q ci -m rcslock commitinfo" \ -"Checking in commitinfo; -${CVSROOT_DIRNAME}/CVSROOT/commitinfo,v <-- commitinfo -new revision: 1\.2; previous revision: 1\.1 -done -${PROG} commit: Rebuilding administrative file database" - cd ..; cd first-dir - - # Simulate (approximately) what a-lock would look like - # if someone else had locked revision 1.1. - sed -e 's/locks; strict;/locks fred:1.1; strict;/' ${CVSROOT_DIRNAME}/first-dir/a-lock,v > a-lock,v - # Cygwin. - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod 644 ${CVSROOT_DIRNAME}/first-dir/a-lock,v" - else - chmod 644 ${CVSROOT_DIRNAME}/first-dir/a-lock,v - fi - dotest reserved-13 "mv a-lock,v ${CVSROOT_DIRNAME}/first-dir/a-lock,v" - # Cygwin. Blah. - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod 444 ${CVSROOT_DIRNAME}/first-dir/a-lock,v" - else - chmod 444 ${CVSROOT_DIRNAME}/first-dir/a-lock,v - fi - echo more stuff >> a-lock - dotest_fail reserved-13b "${testcvs} ci -m '' a-lock" \ -"fred has file a-lock locked for version 1\.1 -${PROG} commit: Pre-commit check failed -${PROG} \[commit aborted\]: correct above errors first!" - # OK, now test "cvs admin -l" in the case where someone - # else has the file locked. - dotest_fail reserved-13c "${testcvs} admin -l a-lock" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/a-lock,v -${PROG} \[admin aborted\]: Revision 1\.1 is already locked by fred" - - dotest reserved-14 "${testcvs} admin -u1.1 a-lock" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/a-lock,v -${PROG} admin: ${CVSROOT_DIRNAME}/first-dir/a-lock,v: revision 1\.1 locked by fred; breaking lock -1\.1 unlocked -done" - dotest reserved-15 "${testcvs} -q ci -m success a-lock" \ -"Checking in a-lock; -${CVSROOT_DIRNAME}/first-dir/a-lock,v <-- a-lock -new revision: 1\.2; previous revision: 1\.1 -done" - - # Now test for a bug involving branches and locks - sed -e 's/locks; strict;/locks fred:1.2; strict;/' ${CVSROOT_DIRNAME}/first-dir/a-lock,v > a-lock,v - chmod 644 ${CVSROOT_DIRNAME}/first-dir/a-lock,v - dotest reserved-16 \ -"mv a-lock,v ${CVSROOT_DIRNAME}/first-dir/a-lock,v" "" - chmod 444 ${CVSROOT_DIRNAME}/first-dir/a-lock,v - dotest reserved-17 "${testcvs} -q tag -b br a-lock" "T a-lock" - dotest reserved-18 "$testcvs -q update -r br a-lock" '[UP] a-lock' - echo edit it >>a-lock - dotest reserved-19 "${testcvs} -q ci -m modify a-lock" \ -"Checking in a-lock; -${CVSROOT_DIRNAME}/first-dir/a-lock,v <-- a-lock -new revision: 1\.2\.2\.1; previous revision: 1\.2 -done" - - # undo commitinfo changes - cd ../CVSROOT - echo '# vanilla commitinfo' >commitinfo - dotest reserved-cleanup-1 "${testcvs} -q ci -m back commitinfo" \ -"Checking in commitinfo; -${CVSROOT_DIRNAME}/CVSROOT/commitinfo,v <-- commitinfo -new revision: 1\.3; previous revision: 1\.2 -done -${PROG} commit: Rebuilding administrative file database" - cd ..; rm -r CVSROOT; cd first-dir - - cd ../.. - rm -r 1 - rm ${TESTDIR}/lockme - rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - diffmerge1) - # Make sure CVS can merge correctly in circumstances where it - # used to mess up (due to a bug which existed in diffutils 2.7 - # and 2.6, but not 2.5, and which has been fixed in CVS's diff - # lib by Paul Eggert, bless his bitty heart). - - # This first test involves two working copies, "mine" and - # "yours", checked out from the same repository at the same - # time. In yours, you remove some text from the end of the - # file and check it in; meanwhile, "me" has commented out some - # lines earlier in the file, and I go to check it in right - # after you checked yours in. CVS naturally tells me the file - # is not up-to-date, so I run cvs update, but it updates - # incorrectly, leaving in the lines of text you just deleted. - # Bad! I'm in too much of a hurry to actually look at the - # file, so I check it in and go home, and so your changes have - # been lost. Later you discover this, and you suspect me of - # deliberately sabotaging your work, so you let all the air - # out of my tires. Only after a series of expensive lawsuits - # and countersuits do we discover that this was all CVS's - # fault. - # - # Luckily, this problem has been fixed now, as our test will - # handily confirm, no doubt: - - # First make a repository containing the original text: - - # We should be here anyway, but cd to it just in case: - cd ${TESTDIR} - - mkdir diffmerge1 - cd diffmerge1 - - # These are the files we both start out with: - mkdir import - cd import - diffmerge_create_older_files - - dotest diffmerge1_import \ - "${testcvs} import -m import diffmerge1 tag1 tag2" \ - "${DOTSTAR}No conflicts created by this import" - cd .. - - # Check out two working copies, one for "you" and one for - # "me". If no branch is used and cvs detects that only one - # of the two people made changes, then cvs does not run the - # merge algorithm. But if a branch is used, then cvs does run - # the merge algorithm (even in this case of only one of the two - # people having made changes). CVS used to have a bug in this - # case. Therefore, it is important to test this case by - # using a branch: - ${testcvs} rtag -b tag diffmerge1 >/dev/null 2>&1 - ${testcvs} checkout -r tag diffmerge1 >/dev/null 2>&1 - mv diffmerge1 yours - ${testcvs} checkout diffmerge1 >/dev/null 2>&1 - mv diffmerge1 mine - - # In your working copy, you'll make changes, and - # then check in your changes before I check in mine: - cd yours - diffmerge_create_your_files - dotest diffmerge1_yours "${testcvs} -q ci -m yours" \ -"Checking in testcase01; -${CVSROOT_DIRNAME}/diffmerge1/testcase01,v <-- testcase01 -new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 -done -Checking in testcase02; -${CVSROOT_DIRNAME}/diffmerge1/testcase02,v <-- testcase02 -new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 -done -Checking in testcase03; -${CVSROOT_DIRNAME}/diffmerge1/testcase03,v <-- testcase03 -new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 -done -Checking in testcase04; -${CVSROOT_DIRNAME}/diffmerge1/testcase04,v <-- testcase04 -new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 -done -Checking in testcase05; -${CVSROOT_DIRNAME}/diffmerge1/testcase05,v <-- testcase05 -new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 -done -Checking in testcase06; -${CVSROOT_DIRNAME}/diffmerge1/testcase06,v <-- testcase06 -new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 -done -Checking in testcase07; -${CVSROOT_DIRNAME}/diffmerge1/testcase07,v <-- testcase07 -new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 -done -Checking in testcase08; -${CVSROOT_DIRNAME}/diffmerge1/testcase08,v <-- testcase08 -new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 -done -Checking in testcase09; -${CVSROOT_DIRNAME}/diffmerge1/testcase09,v <-- testcase09 -new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 -done -Checking in testcase10; -${CVSROOT_DIRNAME}/diffmerge1/testcase10,v <-- testcase10 -new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 -done" - - # Change my copy. Then I - # update, after both my modifications and your checkin: - cd ../mine - diffmerge_create_my_files - dotest diffmerge1_mine "${testcvs} -q update -j tag" \ -"M testcase01 -RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase01,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.1\.2\.1 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase01 -M testcase02 -RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase02,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.1\.2\.1 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase02 -M testcase03 -RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase03,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.1\.2\.1 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase03 -M testcase04 -RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase04,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.1\.2\.1 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase04 -RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase05,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.1\.2\.1 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase05 -RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase06,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.1\.2\.1 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase06 -M testcase07 -RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase07,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.1\.2\.1 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase07 -testcase07 already contains the differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 -M testcase08 -RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase08,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.1\.2\.1 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase08 -M testcase09 -RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase09,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.1\.2\.1 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase09 -M testcase10 -RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase10,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.1\.1\.1\.2\.1 -Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase10" - - # So if your changes didn't make it into my working copy, or - # in any case if the files do not look like the final text - # in the files in directory comp_me, then the test flunks: - cd .. - mkdir comp_me - cd comp_me - diffmerge_create_expected_files - cd .. - rm mine/.#* - - # If you have GNU's version of diff, you may try - # uncommenting the following line which will give more - # fine-grained information about how cvs differed from the - # correct result: - #dotest diffmerge1_cmp "diff -u --recursive --exclude=CVS comp_me mine" '' - dotest diffmerge1_cmp "directory_cmp comp_me mine" - - # Clean up after ourselves: - cd .. - if $keep; then :; else - rm -rf diffmerge1 ${CVSROOT_DIRNAME}/diffmerge1 - fi - ;; - - diffmerge2) - - # FIXME: This test should be rewritten to be much more concise. - # It currently weighs in at something like 600 lines, but the - # same thing could probably be tested in more like 50-100 lines. - mkdir diffmerge2 - - # This tests for another diffmerge bug reported by Martin - # Tomes; actually, his bug was probably caused by an initial - # fix for the bug in test diffmerge1, and likely wasn't ever - # a problem in CVS as long as one was using a normal - # distribution of diff or a version of CVS that has the diff - # lib in it. - # - # Nevertheless, once burned twice cautious, so we test for his - # bug here. - # - # Here is his report, more or less verbatim: - # ------------------------------------------ - # - # Put the attached file (sgrid.h,v) into your repository - # somewhere, check out the module and do this: - # - # cvs update -j Review_Phase_2_Enhancements sgrid.h - # cvs diff -r Review_V1p3 sgrid.h - # - # As there have been no changes made on the trunk there - # should be no differences, however this is output: - # - # % cvs diff -r Review_V1p3 sgrid.h - # Index: sgrid.h - # =================================================================== - # RCS file: /usr/local/repository/play/fred/sgrid.h,v - # retrieving revision 1.1.2.1 - # diff -r1.1.2.1 sgrid.h - # 178a179,184 - # > /*-------------------------------------------------------------- - # > INLINE FUNCTION : HORIZONTALLINES - # > NOTES : Description at the end of the file - # > ----------------------------------------------------------------*/ - # > uint16 horizontalLines( void ); - # > - # - # I did a cvs diff -c -r 1.1 -r 1.1.2.1 sgrid.h and patched those - # differences to sgrid.h version 1.1 and got the correct result - # so it looks like the built in patch is faulty. - # ------------------------------------------------------------------- - # - # This is the RCS file, sgrid.h,v, that he sent: - - echo "head 1.1; -access; -symbols - Review_V1p3:1.1.2.1 - Review_V1p3C:1.1.2.1 - Review_1p3A:1.1.2.1 - Review_V1p3A:1.1.2.1 - Review_Phase_2_Enhancements:1.1.0.2 - Review_V1p2:1.1 - Review_V1p2B:1.1 - Review_V1p2A:1.1 - Review_V1p1:1.1 - Review_1p1:1.1; -locks; strict; -comment @ * @; - - -1.1 -date 97.04.02.11.20.05; author colinl; state Exp; -branches - 1.1.2.1; -next ; - -1.1.2.1 -date 97.06.09.10.00.07; author colinl; state Exp; -branches; -next ; - - -desc -@@ - - -1.1 -log -@Project: DEV1175 -DCN: -Tested By: Colin Law -Reviewed By: -Reason for Change: Initial Revision of all files - -Design Change Details: - -Implications: -@ -text -@/* \$""Header: L:/gpanels/dis/sgrid.h_v 1.1.1.0 24 Jan 1996 14:59:20 PAULT \$ */ -/* - * \$""Log: L:/gpanels/dis/sgrid.h_v \$ - * - * Rev 1.1.1.0 24 Jan 1996 14:59:20 PAULT - * Branched - * - * Rev 1.1 24 Jan 1996 12:09:52 PAULT - * Consolidated 4100 code merged to trunk - * - * Rev 1.0.2.0 01 Jun 1995 14:18:58 DAVEH - * Branched - * - * Rev 1.0 19 Apr 1995 16:32:48 COLINL - * Initial revision. -*/ -/***************************************************************************** -FILE : SGRID.H -VERSION : 2.1 -AUTHOR : Dave Hartley -SYSTEM : Borland C++ -DESCRIPTION : The declaration of the scrolling grid class - -*****************************************************************************/ -#if !defined(__SGRID_H) -#define __SGRID_H - -#if !defined(__SCROLL_H) -#include <scroll.h> -#endif - -#if !defined(__GKI_H) -#include \"gki.h\" -#endif - -#if defined PRINTING_SUPPORT -class Printer; -#endif - -/***************************************************************************** -CLASS : ScrollingGrid -DESCRIPTION: This class inherits from a grid and a scrollable, and - can therefore use all the PUBLIC services provided by these - classes. A description of these can be found in - GRID.H and SCROLL.H. - A scrolling grid is a set of horizontal and vertical lines - that scroll and continually update to provide a complete grid - -*****************************************************************************/ - -class ScrollingGrid : public Scrollable -{ - public: -#if defined _WINDOWS -/*--------------------------------------------------------------------------- -FUNCTION : CONSTRUCTOR -DESCRIPTION : sets up the details of the grid, ready for painting -ARGUMENTS : name : sgColour - - the colour of the grid - sgLineType - - the syle of line - sgHorizontalTotal - - the total number of horizontal grid lines - verticalSpacingMin - - the min distance between the vertical grid lines - on the scrolling axis - currentTimestamp - - timestamp value now - ticksPerSecond - - number of timestamp ticks per second - ticksPerPixel - - number of timestamp ticks per pixel required - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - ScrollingGrid( GkiColour sgColour, GkiLineType sgLineType, - uint16 sgHorizontalTotal, - uint16 verticalSpacingMin, uint32 currentTimestamp, - uint16 ticksPerSecond, uint32 ticksPerPixel ); -#else -/*--------------------------------------------------------------------------- -FUNCTION : CONSTRUCTOR -DESCRIPTION : sets up the details of the grid, ready for painting -ARGUMENTS : name : sgColour - - the colour of the grid - sgLineType - - the syle of line - sgHorizontalTotal ( THE MAX NUMBER OF LINES IS 100 ) - - the total number of horizontal grid lines - sgVerticalSpacing - - the distance between the vertical grid lines - on the scrolling axis - -RETURN : None -NOTES : If the caller does not get the total grid lines value, synced - with the overall size of the viewport, the spacing between - grid lines will not be consistent. - ----------------------------------------------------------------------------*/ - ScrollingGrid( GkiColour sgColour, GkiLineType sgLineType - , uint16 sgHorizontalTotal, uint16 sgVerticalSpacing ); -#endif -/*--------------------------------------------------------------------------- -FUNCTION : DESTRUCTOR -DESCRIPTION : tidies it all up -ARGUMENTS : name : - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - ~ScrollingGrid( void ); - -/*--------------------------------------------------------------------------- -FUNCTION : ATTACH -DESCRIPTION : This service overloads the base class service, as it does - additional work at the time of attachment. - -ARGUMENTS : name : tDrawingArea - - the scrolled viewport to attach this trend to - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void attach( SViewport *tDrawingArea ); - -#if defined _WINDOWS -/*--------------------------------------------------------------------------- -FUNCTION : calculateVerticalSpacing -DESCRIPTION : determines optimum spacing along time axis -ARGUMENTS : -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void calculateVerticalSpacing(); - -/*--------------------------------------------------------------------------- -FUNCTION : gridSpacingTicks -DESCRIPTION : Provides the grid spacing in the time axis in ticks -ARGUMENTS : -RETURN : Number of ticks -NOTES : ----------------------------------------------------------------------------*/ - uint32 gridSpacingTicks(); - -#endif - -/*--------------------------------------------------------------------------- -INLINE FUNCTION : HORIZONTALLINES -NOTES : Description at the end of the file ----------------------------------------------------------------------------*/ - uint16 horizontalLines( void ); - -#if defined _WINDOWS -// In Windows the OnDraw() function replaces paint() -/*--------------------------------------------------------------------------- -FUNCTION : ScrollingGrid OnDraw -DESCRIPTION : Paints the given area of the grid. - Pure virtual -ARGUMENTS : pDC pointer to the device context to use for display - Note that the device context operates in the coords - of the window owning the viewport -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - virtual void OnDraw( CDC *pDC ); - -#else // not Windows - -/*--------------------------------------------------------------------------- -FUNCTION : PAINT -DESCRIPTION : This extends the standard grid paint method to paint the - viewport relative to its current position. - -ARGUMENTS : name : - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void paint( void ); -#endif - -/*--------------------------------------------------------------------------- -FUNCTION : P A I N T T E X T M A R K E R S -DESCRIPTION : this service allow the text markers to be painted seperatley - from the grid lines - -ARGUMENTS : name : - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void paintTextMarkers(); - -#if defined PRINTING_SUPPORT -/*--------------------------------------------------------------------------- -FUNCTION : P R I N T -DESCRIPTION : This print service prints a grid marker ( being either a - timestamp or a date, IF there is one at the plot position - given - -ARGUMENTS : name : - displayPosition - - Where in the log to look to see if there is an - entry to print - - - printerPtr - the printer to print to - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void print( uint16 currentPrintPos, Printer *printerPtr ); -#endif - -/*--------------------------------------------------------------------------- -FUNCTION : S E T D R I V E D I R E C T I O N -DESCRIPTION : Sets direction for update and scrolling forwards or backwards -ARGUMENTS : direction - required direction -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void setDriveDirection( ScrollDirection direction ); - -/*--------------------------------------------------------------------------- -FUNCTION : S E T U P -DESCRIPTION : service that will setup the grid prior to a paint - -ARGUMENTS : name : - - newTimestamp - - - - newTimeBase - the number of ticks that represent a plot point on - the trendgraph. - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void setup( uint32 newTimestamp, uint32 newTimeBase ); - -#if defined PRINTING_SUPPORT -/*--------------------------------------------------------------------------- -FUNCTION : S E T U P F O R P R I N T -DESCRIPTION : This service iis to be called prior to printing. It allows - the grid to prepare its markers ready for the print - commands - -ARGUMENTS : name : - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void setupForPrint(); -#endif - -/*--------------------------------------------------------------------------- -FUNCTION : UPDATE -DESCRIPTION : When this service is called it will calculate what needs to - be painted and fill in the display again. - -ARGUMENTS : name : timeStamp - - the reference time of this update. - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void update( uint32 timeStamp ); - -/*--------------------------------------------------------------------------- -FUNCTION : U P D A T E B U F F E R -DESCRIPTION : When a display update is not required, use this method. It - updates the internal data ready for a call to paint that - will then show the grid in the right position - -ARGUMENTS : name : - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void updateBuffer( void ); - - private: - -/*--------------------------------------------------------------------------- -FUNCTION : M A K E G R I D M A R K E R -DESCRIPTION : service that perpares a string for display. The string will - either be a short date, or short time. this is determined - by the current setting of the dateMarker flag - -ARGUMENTS : name : timestampVal - - the value to convert - - storePtr - - the place to put the string - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void makeGridMarker( uint32 timestampVal, char *storePtr ); - -/*--------------------------------------------------------------------------- -FUNCTION : P A I N T G R I D M A R K E R -DESCRIPTION : given a position will put the string on the display - -ARGUMENTS : name : - yPos - - were it goes on the Y-axis - - gridMarkerPtr - - what it is - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void paintGridMarker( uint16 yPos, char *gridMarkerPtr ); - -#if defined _WINDOWS -/*--------------------------------------------------------------------------- -FUNCTION : PAINTHORIZONTALLINES -DESCRIPTION : responsible for painting the grids horizontal lines -ARGUMENTS : pRectToDraw pointer to rectangle that needs refreshing. - in viewport coords - pDC pointer to device context to use - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void paintHorizontalLines(RectCoords* pRectToDraw, CDC* pDC ); -#else -/*--------------------------------------------------------------------------- -FUNCTION : PAINTHORIZONTALLINES -DESCRIPTION : responsible for painting the grids horizontal lines -ARGUMENTS : name: xStart - - the starting X co-ordinate for the horizontal line - xEnd - - the ending X co-ordinate for the horizontal line - -RETURN : None -NOTES : Remember lines are drawn from origin. The origin in a - horizontal viewport will be the top. ----------------------------------------------------------------------------*/ - void paintHorizontalLines( uint16 xStart, uint16 xEnd ); -#endif - -#if defined _WINDOWS -/*--------------------------------------------------------------------------- -FUNCTION : PAINTVERTICALLINES -DESCRIPTION : responsible for painting the grids vertical lines -ARGUMENTS : pRectToDraw pointer to rectangle that needs refreshing. - in viewport coords - offset offset from rhs that rightmost line would be - drawn if rectangle included whole viewport - pDC pointer to device context to use -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void paintVerticalLines( RectCoords* pRectToDraw, uint16 offset, - CDC* pDC ); -#else -/*--------------------------------------------------------------------------- -FUNCTION : PAINTVERTICALLINES -DESCRIPTION : responsible for painting the grids vertical lines -ARGUMENTS : name : yStart - - the starting Y co-ordinate for the vertical line - yEnd - - the ending Y co-ordinate for the vertical line - offset - - a starting point offset that determines at what X - position the first line will be drawn - - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void paintVerticalLines( uint16 yStart, uint16 yEnd, uint16 offset ); -#endif - -#if defined _WINDOWS -/*--------------------------------------------------------------------------- -FUNCTION : PAINTVERTICALLINE -DESCRIPTION : paints one line at the position specified, and length -ARGUMENTS : name : yStart - - the starting point on the y axis for the line - yEnd - - the end point on the y axis for the line - xPosition - - The horizontal offset from the start of the viewport - pDC pointer to device context to use - -RETURN : None -NOTES : There is not an equivalent horizontal method as yet. This - is a seperate method because the service is useful to a - derivation of this class ----------------------------------------------------------------------------*/ - void paintVerticalLine( uint16 yStart, uint16 yEnd - , uint16 xPosition, CDC *pDC ); -#else -/*--------------------------------------------------------------------------- -FUNCTION : PAINTVERTICALLINE -DESCRIPTION : paints one line at the position specified, and length -ARGUMENTS : name : yStart - - the starting point on the y axis for the line - yEnd - - the end point on the y axis for the line - xPosition - - The horizontal offset from the start of the viewport - -RETURN : None -NOTES : There is not an equivalent horizontal method as yet. This - is a seperate method because the service is useful to a - derivation of this class ----------------------------------------------------------------------------*/ - void paintVerticalLine( uint16 yStart, uint16 yEnd - , uint16 xPosition ); -#endif - -/*--------------------------------------------------------------------------- -INLINE FUNCTION : VERTICALSPACING -NOTES : Description at the end of the file ----------------------------------------------------------------------------*/ - uint16 verticalSpacing( void ); - - - // Position in viewport that we are now writing to if going forwards - // Note that if this is greater than viewport length then we have - // just scrolled and value must be adjusted before use. - sint16 forwardsOutputPosition; - - // Position in viewport that we are now writing to if going backwards - // Note that if this is less than zero then we have - // just scrolled and value must be adjusted before use. - sint16 backwardsOutputPosition; - - // position in grid cycle of forwards output position. - // if zero then it is time to output a grid line - sint16 forwardsIntervalCount; - - // position in grid cycle of forwards output position. - // if zero then it is time to output a grid line - sint16 backwardsIntervalCount; - - uint32 lastUpdateTimestamp; - uint32 timeBase; // ticks per pixel - uint16 currentOutputPosition; - uint16 gridTimestampSpacing; - uint16 intervalCount; - uint16 horizontalTotal; - uint16 vSpacing; -#if defined PRINTING_SUPPORT - uint16 numberOfGridMarkersPrinted; -#endif - bool firstTime; // indicates first time through - bool dateMarker; - - GkiLineType lineType; - GkiColour gridColour; - - #if defined _WINDOWS - uint16 ticksPerSec; // number of time ticks per second - uint16 vSpacingMin; // minimum pixels per division along time axis - CPen *pPen; // the pen to use for drawing in windows - #endif - -}; - - -/***************************************************************************** - I N L I N E F U N C T I O N S -*****************************************************************************/ - -/*--------------------------------------------------------------------------- -FUNCTION : HORIZONTALLINES -DESCRIPTION : supplies the number of horizontal lines in the grid -ARGUMENTS : name : - -RETURN : -NOTES : ----------------------------------------------------------------------------*/ -inline uint16 ScrollingGrid::horizontalLines( void ) -{ - return( horizontalTotal ); -} -/*--------------------------------------------------------------------------- -FUNCTION : VERTICALSPACING -DESCRIPTION : returns the distance between adjacent vertical lines -ARGUMENTS : name : - -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ -inline uint16 ScrollingGrid::verticalSpacing( void ) -{ - return( vSpacing ); -} - -#endif -@ - - -1.1.2.1 -log -@DEV1194:DS4 Provision of major and minor grid lines -@ -text -@d1 1 -a1 1 -/* \$""Header: /usr/local/repository/cmnsrc/review/src/sgrid.h,v 1.1 1997/04/02 11:20:05 colinl Exp \$ */ -d3 1 -a3 12 - * \$""Log: sgrid.h,v \$ - * Revision 1.1 1997/04/02 11:20:05 colinl - * Project: DEV1175 - * DCN: - * Tested By: Colin Law - * Reviewed By: - * Reason for Change: Initial Revision of all files - * - * Design Change Details: - * - * Implications: - * -d58 6 -a63 5 -ARGUMENTS : name : majorColour colour for major grid lines - minorColour colour for minor grid lines - sgLineType line type for minor grid lines - yMajorGridLines number of major y lines on grid - yMinorGridLines number of major y lines on grid -d77 2 -a78 3 - ScrollingGrid( GkiColour majorColour, GkiColour minorColour, - GkiLineType sgLineType, - uint16 yMajorGridLines, uint16 yMinorGridLines, -a137 17 -FUNCTION : DrawHorizontalGridLines - -DESCRIPTION : Draws major or minor grid lines -ARGUMENTS : pDC device context - pPen pen to use - numLines total lines required - yLow, yHigh, xLow, xHigh rectangle to draw in - yMax max y value -RETURN : None -NOTES : ----------------------------------------------------------------------------*/ - void DrawHorizontalGridLines( CDC* pDC, CPen* pPen, - uint16 numLines, - uint16 yLow, uint16 yHigh, uint16 xLow, uint16 xHigh, - uint16 yMax ); - -/*--------------------------------------------------------------------------- -d148 6 -d448 1 -a448 2 - uint16 m_yMajorGridLines; - uint16 m_yMinorGridLines; -d456 2 -a457 3 - GkiLineType lineType; // line type for minor grid lines - GkiColour m_majorColour; - GkiColour m_minorColour; -d462 1 -a462 2 - CPen *pMajorPen; // pen to use for drawing major grid lines - CPen *pMinorPen; // pen to use for drawing minor grid lines -d472 12 -@" > diffmerge2/sgrid.h,v - - # We have to put the RCS file in the repository by hand for - # this test: - mkdir ${CVSROOT_DIRNAME}/diffmerge2 - cp diffmerge2/sgrid.h,v ${CVSROOT_DIRNAME}/diffmerge2/sgrid.h,v - rm -rf diffmerge2 - dotest diffmerge2_co \ - "${testcvs} co diffmerge2" "${DOTSTAR}U ${DOTSTAR}" - cd diffmerge2 - dotest diffmerge2_update \ - "${testcvs} update -j Review_Phase_2_Enhancements sgrid.h" \ - "${DOTSTAR}erging ${DOTSTAR}" - # This is the one that counts -- there should be no output: - dotest diffmerge2_diff \ - "${testcvs} diff -r Review_V1p3 sgrid.h" '' - - cd .. - rm -rf diffmerge2 - rm -rf ${CVSROOT_DIRNAME}/diffmerge2 - ;; - - release) - # Tests of "cvs release", particularly multiple arguments. - # Other CVS release tests: - # info-cleanup-0 for "cvs -n release". - # ignore-193 for the text of the question that cvs release asks. - # Also for interactions with cvsignore. - # basicc: "-d .", global -Q, no arguments (is a noop), - # "cvs release" without -d, multiple arguments. - # dirs-4: repository directory has been deleted. - # modules2-6: multiple arguments. - - # First the usual setup; create a directory first-dir. - mkdir 1; cd 1 - dotest release-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest release-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - mkdir dir1 - dotest release-3 "${testcvs} add dir1" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir1 added to the repository" - mkdir dir2 - dotest release-4 "${testcvs} add dir2" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir2 added to the repository" - cd dir2 - mkdir dir3 - dotest release-5 "${testcvs} add dir3" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir2/dir3 added to the repository" - - cd ../.. - dotest release-6 "${testcvs} release -d first-dir/dir2/dir3 first-dir/dir1" \ -"You have .0. altered files in this repository. -Are you sure you want to release (and delete) directory .first-dir/dir2/dir3.: \ -You have .0. altered files in this repository. -Are you sure you want to release (and delete) directory .first-dir/dir1.: " <<EOF -yes -yes -EOF - dotest_fail release-7 "test -d first-dir/dir1" '' - dotest_fail release-8 "test -d first-dir/dir2/dir3" '' - dotest release-9 "${testcvs} update" \ -"${PROG} update: Updating \. -${PROG} update: Updating first-dir -${PROG} update: Updating first-dir/dir2" - - cd first-dir - mkdir dir1 - dotest release-10 "${testcvs} add dir1" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir1 added to the repository" - cd dir2 - mkdir dir3 - dotest release-11 "${testcvs} add dir3" \ -"Directory ${CVSROOT_DIRNAME}/first-dir/dir2/dir3 added to the repository" - - cd ../.. - dotest release-12 "${testcvs} release first-dir/dir2/dir3 first-dir/dir1" \ -"You have .0. altered files in this repository. -Are you sure you want to release directory .first-dir/dir2/dir3.: .. .release. aborted by user choice. -You have .0. altered files in this repository. -Are you sure you want to release directory .first-dir/dir1.: " <<EOF -no -yes -EOF - dotest release-13 "${testcvs} release first-dir/dir2/dir3 first-dir/dir2" \ -"You have .0. altered files in this repository. -Are you sure you want to release directory .first-dir/dir2/dir3.: \ -You have .0. altered files in this repository. -Are you sure you want to release directory .first-dir/dir2.: " <<EOF -yes -yes -EOF - dotest release-14 "test -d first-dir/dir1" '' - dotest release-15 "test -d first-dir/dir2/dir3" '' - rm -rf first-dir/dir1 first-dir/dir2 - - dotest release-16 "${testcvs} update" \ -"${PROG} update: Updating \. -${PROG} update: Updating first-dir" - - # Check to make sure release isn't overwriting a - # CVS/Entries file in the current directory (using data - # from the released directory). - - # cvs 1.11 (remote) fails on release-21 (a message about - # chdir into the removed directory), although it seemingly - # unedits and removes the directory correctly. If - # you manually continue, it then fails on release-22 do - # to the messed up CVS/Entries file from release-21. - cd first-dir - mkdir second-dir - dotest release-18 "$testcvs add second-dir" \ -"Directory $CVSROOT_DIRNAME/first-dir/second-dir added to the repository" - - cd second-dir - touch file1 - dotest release-19 "$testcvs -Q add file1" - dotest release-20 '$testcvs -q ci -m add' \ -"RCS file: $CVSROOT_DIRNAME/first-dir/second-dir/file1,v -done -Checking in file1; -$CVSROOT_DIRNAME/first-dir/second-dir/file1,v <-- file1 -initial revision: 1\.1 -done" - dotest release-21 "$testcvs edit file1" - cd .. - dotest release-22 "echo yes | $testcvs release -d second-dir" \ -"You have \[0\] altered files in this repository. -Are you sure you want to release (and delete) directory \`second-dir': " - dotest release-23 "$testcvs -q update -d" "U second-dir/file1" - dotest release-24 "$testcvs edit" - - cd ../.. - rm -rf 1 $CVSROOT_DIRNAME/first-dir - ;; - - - - recase) - # - # Some tests of behavior which broke at one time or another when run - # from case insensitive clients against case sensitive servers. - # - # These tests are namned according to the following convention: - # - # ci Client (sandbox filesystem) case Insensitive - # cs Client (sandbox filesystem) case Sensitive - # si Server (repository filesystem) case Insensitive - # ss Server (repository filesystem) case Sensitive - # - - mkdir 1; cd 1 - - # First, we will expect different results for a few of these tests - # based on whether the repository is on a case sensitive filesystem - # or not and whether the sandbox is on a case sensitive filesystem or - # not, so determine which cases we are dealing with: - echo file >file - echo FiLe >FiLe - if cmp file FiLe >/dev/null; then - client_sensitive=false - else - client_sensitive=: - fi - if test -n "$remotehost"; then - $CVS_RSH $remotehost 'echo file >file' - $CVS_RSH $remotehost 'echo FiLe >FiLe' - if $CVS_RSH $remotehost 'cmp file FiLe >/dev/null'; then - server_sensitive=false - else - server_sensitive=: - fi - else - server_sensitive=$client_sensitive - fi - - # The first test (recase-1 & recase-2) is for a remove of a file then - # a readd in a different case. - mkdir $CVSROOT_DIRNAME/first-dir - dotest recase-init-1 "$testcvs -Q co first-dir" - cd first-dir - - echo this file has no content >file - dotest recase-init-2 "$testcvs -Q add file" - dotest recase-init-3 "$testcvs -Q ci -madd" \ -"RCS file: $CVSROOT_DIRNAME/first-dir/file,v -done -Checking in file; -$CVSROOT_DIRNAME/first-dir/file,v <-- file -initial revision: 1\.1 -done" - dotest recase-init-4 "$testcvs -Q tag first" - - # Now remove the file. - dotest recase-init-5 "$testcvs -Q rm -f file" - dotest recase-init-6 "$testcvs -Q ci -mrm" \ -"Removing file; -$CVSROOT_DIRNAME/first-dir/file,v <-- file -new revision: delete; previous revision: 1\.1 -done" - - # Now the test - readd in a different case. - echo this file needs some content >FiLe - if $server_sensitive; then - dotest recase-1ss "$testcvs add FiLe" \ -"$PROG add: scheduling file \`FiLe' for addition -$PROG add: use '$PROG commit' to add this file permanently" - dotest recase-2ss "$testcvs -q ci -mrecase" \ -"RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v -done -Checking in FiLe; -$CVSROOT_DIRNAME/first-dir/FiLe,v <-- FiLe -initial revision: 1\.1 -done" - else # server insensitive - dotest recase-1si "$testcvs add FiLe" \ -"$PROG add: Re-adding file \`FiLe' (in place of dead revision 1\.2)\. -$PROG add: use '$PROG commit' to add this file permanently" - dotest recase-2si "$testcvs -q ci -mrecase" \ -"Checking in FiLe; -$CVSROOT_DIRNAME/first-dir/FiLe,v <-- FiLe -new revision: 1\.3; previous revision: 1\.2 -done" - fi - - # Now verify that a checkout will still work - cd ../.. - mkdir 2; cd 2 - dotest recase-3 "$testcvs -q co first-dir" \ -"U first-dir/FiLe" - - cd first-dir - # Prove that we can still get status and log information on - # conflicting case files (1 in Attic, one in parent). - if $remote; then - if $client_sensitive; then - file=file - fIlE=fIlE - else # client insensitive - # Because FiLe is present on a case insensitive client, it is the - # only one ever found and queried or altered. - file=FiLe - fIlE=FiLe - fi - else # ! $remote - file=file - fIlE=fIlE - fi - if $server_sensitive; then - if $client_sensitive; then - # Client finds Entry only for FiLe. Others returned by server. - dotest recase-4sscs "$testcvs status file" \ -"=================================================================== -File: no file file Status: Up-to-date - - Working revision: No entry for file - Repository revision: 1\.2 $CVSROOT_DIRNAME/first-dir/Attic/file,v" - dotest recase-5sscs "$testcvs log file" \ -" -RCS file: $CVSROOT_DIRNAME/first-dir/Attic/file,v -Working file: file -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - first: 1\.1 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: $username; state: dead; lines: +0 -0 -rm ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -add -=============================================================================" - dotest recase-6sscs "$testcvs status FiLe" \ -"=================================================================== -File: FiLe Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest recase-7sscs "$testcvs log FiLe" \ -" -RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v -Working file: FiLe -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -recase -=============================================================================" - else # server sensitive && client insensitive - # Client finds same Entry for file & FiLe. - dotest recase-4ssci "$testcvs status file" \ -"=================================================================== -File: FiLe Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest recase-5ssci "$testcvs log file" \ -" -RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v -Working file: FiLe -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -recase -=============================================================================" - dotest recase-6ss "$testcvs status FiLe" \ -"=================================================================== -File: FiLe Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest recase-7ss "$testcvs log FiLe" \ -" -RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v -Working file: FiLe -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -recase -=============================================================================" - fi - else # server insensitive - # There is only one archive when the server is insensitive, but the - # printed file/archive name can vary. - dotest recase-4si "$testcvs status file" \ -"=================================================================== -File: $file Status: Up-to-date - - Working revision: 1\.3.* - Repository revision: 1\.3 $CVSROOT_DIRNAME/first-dir/$file,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest recase-5si "$testcvs log file" \ -" -RCS file: $CVSROOT_DIRNAME/first-dir/$file,v -Working file: $file -head: 1\.3 -branch: -locks: strict -access list: -symbolic names: - first: 1\.1 -keyword substitution: kv -total revisions: 3; selected revisions: 3 -description: ----------------------------- -revision 1\.3 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; lines: +1 -1 -recase ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: $username; state: dead; lines: +0 -0 -rm ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -add -=============================================================================" - dotest recase-6si "$testcvs status FiLe" \ -"=================================================================== -File: FiLe Status: Up-to-date - - Working revision: 1\.3.* - Repository revision: 1\.3 $CVSROOT_DIRNAME/first-dir/FiLe,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest recase-7si "$testcvs log FiLe" \ -" -RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v -Working file: FiLe -head: 1\.3 -branch: -locks: strict -access list: -symbolic names: - first: 1\.1 -keyword substitution: kv -total revisions: 3; selected revisions: 3 -description: ----------------------------- -revision 1\.3 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; lines: +1 -1 -recase ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: $username; state: dead; lines: +0 -0 -rm ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -add -=============================================================================" - fi - - # And when the file does not exist on the client, we go with the - # client Entries match. - if $client_sensitive && $server_sensitive; then - dotest recase-8sscs "$testcvs status fIlE" \ -"$PROG status: nothing known about fIlE -=================================================================== -File: no file fIlE Status: Unknown - - Working revision: No entry for fIlE - Repository revision: No revision control file" - else # !$client_sensitive || !$server_sensitive - dotest recase-8anyi "$testcvs status fIlE" \ -"=================================================================== -File: $fIlE Status: Up-to-date - - Working revision: 1\.[0-9]*.* - Repository revision: 1\.[0-9]* $CVSROOT_DIRNAME/first-dir/$fIlE,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - fi - - # and an update - if $server_sensitive; then - dotest recase-9ss "$testcvs -q up -rfirst" \ -"$PROG update: FiLe is no longer in the repository -U file" - - if $client_sensitive; then - dotest recase-10sscs "$testcvs -q up -A" \ -"U FiLe -$PROG update: file is no longer in the repository" - else # client insensitive - # FIXCVS: This should remove the offending file first. - dotest_fail recase-10ssci "$testcvs -q up -A" \ -"$PROG update: move away \./FiLe; it is in the way -C FiLe -$PROG update: file is no longer in the repository" - - cd .. - rm -r first-dir - dotest recase-11ssci "$testcvs -q co first-dir" \ -"U first-dir/FiLe" - cd first-dir - fi - - # - # See what happens when cased names clash. - # - - # Copy the archive - if test -n "$remotehost"; then - $CVS_RSH $remotehost "cp $CVSROOT_DIRNAME/first-dir/FiLe,v \ - $CVSROOT_DIRNAME/first-dir/FILE,v" - else - cp $CVSROOT_DIRNAME/first-dir/FiLe,v \ - $CVSROOT_DIRNAME/first-dir/FILE,v - fi - - if $client_sensitive; then - dotest recase-12sscs "$testcvs -q up" "U FILE" - else # client insensitive - dotest_fail recase-12ssci "$testcvs -q up" \ -"$PROG update: move away \./FILE; it is in the way -C FILE" - fi - else # server insensitive - dotest recase-9si "$testcvs -q up -rfirst" "U FiLe" - dotest recase-10si "$testcvs -q up -A" "U FiLe" - fi - - # Prove that we can still get status and log information on - # conflicting case files (1 in Attic, two in parent). - if $server_sensitive; then - if $client_sensitive; then - # Client finds Entry only for FiLe. Others returned by server. - dotest recase-13sscs "$testcvs status file" \ -"=================================================================== -File: no file file Status: Up-to-date - - Working revision: No entry for file - Repository revision: 1\.2 $CVSROOT_DIRNAME/first-dir/Attic/file,v" - dotest recase-14sscs "$testcvs log file" \ -" -RCS file: $CVSROOT_DIRNAME/first-dir/Attic/file,v -Working file: file -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - first: 1\.1 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: $username; state: dead; lines: +0 -0 -rm ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -add -=============================================================================" - dotest recase-15sscs "$testcvs status FiLe" \ -"=================================================================== -File: FiLe Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest recase-16sscs "$testcvs log FiLe" \ -" -RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v -Working file: FiLe -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -recase -=============================================================================" - dotest recase-17sscs "$testcvs status FILE" \ -"=================================================================== -File: FILE Status: Up-to-date - - Working revision: 1.1.* - Repository revision: 1.1 ${CVSROOT_DIRNAME}/first-dir/FILE,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest recase-18sscs "$testcvs log FILE" \ -" -RCS file: $CVSROOT_DIRNAME/first-dir/FILE,v -Working file: FILE -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -recase -=============================================================================" - else # $server_sensitive && !$client_sensitive - # Client finds same Entry for file & FiLe. - dotest recase-13ssci "$testcvs status file" \ -"=================================================================== -File: FiLe Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest recase-16ssci "$testcvs log FiLe" \ -" -RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v -Working file: FiLe -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -recase -=============================================================================" - dotest recase-17ssci "$testcvs status FILE" \ -"=================================================================== -File: FiLe Status: Up-to-date - - Working revision: 1\.1.* - Repository revision: 1\.1 $CVSROOT_DIRNAME/first-dir/FiLe,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - dotest recase-18ssci "$testcvs log FILE" \ -" -RCS file: $CVSROOT_DIRNAME/first-dir/FiLe,v -Working file: FiLe -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: $username; state: Exp; -recase -=============================================================================" - fi - else # !$server_sensitive - # Skip these when the server is case insensitive - nothing - # has changed since recase-[4-7]si - : - fi - - if $client_sensitive && $server_sensitive; then - dotest recase-19sscs "$testcvs status fIlE" \ -"$PROG status: nothing known about fIlE -=================================================================== -File: no file fIlE Status: Unknown - - Working revision: No entry for fIlE - Repository revision: No revision control file" - else # !$client_sensitive || !$server_sensitive - dotest recase-19anyi "$testcvs status fIlE" \ -"=================================================================== -File: $fIlE Status: Up-to-date - - Working revision: 1\.[0-9]*.* - Repository revision: 1\.[0-9]* $CVSROOT_DIRNAME/first-dir/$fIlE,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none)" - fi - - # And last but not least, prove that a checkout is still possible. - cd ../.. - mkdir 3; cd 3 - if $server_sensitive; then - if $client_sensitive; then - dotest recase-20sscs "$testcvs -q co first-dir" \ -"U first-dir/FILE -U first-dir/FiLe" - else # $server_senstive && !$client_sensitive - dotest_fail recase-20ssci "$testcvs -q co first-dir" \ -"U first-dir/FILE -$PROG checkout: move away first-dir/FiLe; it is in the way -C first-dir/FiLe" - fi - else # !$server_sensitive - # Skip these since nothing has changed. - : - fi - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd .. - rm -r 1 2 3 - if $server_sensitive && test -n "$remotehost"; then - # It is necessary to remove one of the case-conflicted files before - # recursively removing the rest under Cygwin on a Samba share or - # Samba returns a permission denied error due to its case - # confusion. - $CVS_RSH $remotehost "rm -f $CVSROOT_DIRNAME/first-dir/FILE,v" - fi - rm -rf $CVSROOT_DIRNAME/first-dir - ;; - - - - multiroot) - # - # set up two repositories - # - - CVSROOT1_DIRNAME=${TESTDIR}/root1 - CVSROOT2_DIRNAME=${TESTDIR}/root2 - CVSROOT1=`newroot $CVSROOT1_DIRNAME` - CVSROOT2=`newroot $CVSROOT2_DIRNAME` - testcvs1="${testcvs} -d ${CVSROOT1}" - testcvs2="${testcvs} -d ${CVSROOT2}" - - dotest multiroot-setup-1 "mkdir $CVSROOT1_DIRNAME $CVSROOT2_DIRNAME" - dotest multiroot-setup-2 "$testcvs -d$CVSROOT1_DIRNAME init" - dotest multiroot-setup-3 "$testcvs -d$CVSROOT2_DIRNAME init" - - # - # create some directories in root1 - # - mkdir 1; cd 1 - dotest multiroot-setup-4 "${testcvs1} co -l ." \ -"${PROG} checkout: Updating ." - mkdir mod1-1 mod1-2 - dotest multiroot-setup-5 "${testcvs1} add mod1-1 mod1-2" \ -"Directory ${CVSROOT1_DIRNAME}/mod1-1 added to the repository -Directory ${CVSROOT1_DIRNAME}/mod1-2 added to the repository" - echo file1-1 > mod1-1/file1-1 - echo file1-2 > mod1-2/file1-2 - dotest multiroot-setup-6 "${testcvs1} add mod1-1/file1-1 mod1-2/file1-2" \ -"${PROG} add: scheduling file .mod1-1/file1-1. for addition -${PROG} add: scheduling file .mod1-2/file1-2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest multiroot-setup-7 "${testcvs1} commit -m is" \ -"${PROG} [a-z]*: Examining \. -${PROG} [a-z]*: Examining mod1-1 -${PROG} [a-z]*: Examining mod1-2 -RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v -done -Checking in mod1-1/file1-1; -${CVSROOT1_DIRNAME}/mod1-1/file1-1,v <-- file1-1 -initial revision: 1.1 -done -RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v -done -Checking in mod1-2/file1-2; -${CVSROOT1_DIRNAME}/mod1-2/file1-2,v <-- file1-2 -initial revision: 1.1 -done" - cd .. - rm -rf 1 - - # - # create some directories in root2 - # - mkdir 1; cd 1 - dotest multiroot-setup-8 "${testcvs2} co -l ." \ -"${PROG} checkout: Updating ." - mkdir mod2-1 mod2-2 - dotest multiroot-setup-9 "${testcvs2} add mod2-1 mod2-2" \ -"Directory ${CVSROOT2_DIRNAME}/mod2-1 added to the repository -Directory ${CVSROOT2_DIRNAME}/mod2-2 added to the repository" - echo file2-1 > mod2-1/file2-1 - echo file2-2 > mod2-2/file2-2 - dotest multiroot-setup-6 "${testcvs2} add mod2-1/file2-1 mod2-2/file2-2" \ -"${PROG} add: scheduling file .mod2-1/file2-1. for addition -${PROG} add: scheduling file .mod2-2/file2-2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest multiroot-setup-10 "${testcvs2} commit -m anyone" \ -"${PROG} [a-z]*: Examining \. -${PROG} [a-z]*: Examining mod2-1 -${PROG} [a-z]*: Examining mod2-2 -RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v -done -Checking in mod2-1/file2-1; -${CVSROOT2_DIRNAME}/mod2-1/file2-1,v <-- file2-1 -initial revision: 1.1 -done -RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v -done -Checking in mod2-2/file2-2; -${CVSROOT2_DIRNAME}/mod2-2/file2-2,v <-- file2-2 -initial revision: 1.1 -done" - cd .. - rm -rf 1 - - # check out a few directories, from simple/shallow to - # complex/deep - mkdir 1; cd 1 - - # OK, this case is kind of weird. If we just run things from - # here, without CVS/Root, then CVS will contact the server - # mentioned in CVSROOT (which is irrelevant) which will print - # some messages. Our workaround is to make sure we have a - # CVS/Root file at top level. In the future, it is possible - # the best behavior will be to extend the existing behavior - # ("being called from a directory without CVS administration - # has always meant to process each of the sub-dirs") to also - # do that if there is no CVSROOT, CVS/Root, or -d at top level. - # - # The local case could stumble through the tests without creating - # the top-level CVS/Root, but we create it for local and for - # remote to reduce special cases later in the test. - dotest multiroot-workaround "${testcvs1} -q co -l ." "" - - dotest multiroot-setup-11 "${testcvs1} co mod1-1 mod1-2" \ -"${PROG} checkout: Updating mod1-1 -U mod1-1/file1-1 -${PROG} checkout: Updating mod1-2 -U mod1-2/file1-2" - dotest multiroot-setup-12 "${testcvs2} co mod2-1 mod2-2" \ -"${PROG} checkout: Updating mod2-1 -U mod2-1/file2-1 -${PROG} checkout: Updating mod2-2 -U mod2-2/file2-2" - cd mod1-2 - dotest multiroot-setup-13 "${testcvs2} co mod2-2" \ -"${PROG} checkout: Updating mod2-2 -U mod2-2/file2-2" - cd .. - cd mod2-2 - dotest multiroot-setup-14 "${testcvs1} co mod1-2" \ -"${PROG} checkout: Updating mod1-2 -U mod1-2/file1-2" - cd .. - - # - # Make sure that the Root and Repository files contain the - # correct information. - # - dotest multiroot-cvsadm-1a "cat mod1-1/CVS/Root" "${CVSROOT1}" - dotest multiroot-cvsadm-1b "cat mod1-1/CVS/Repository" "mod1-1" - dotest multiroot-cvsadm-2a "cat mod2-1/CVS/Root" "${CVSROOT2}" - dotest multiroot-cvsadm-2b "cat mod2-1/CVS/Repository" "mod2-1" - dotest multiroot-cvsadm-3a "cat mod1-2/CVS/Root" "${CVSROOT1}" - dotest multiroot-cvsadm-3b "cat mod1-2/CVS/Repository" "mod1-2" - dotest multiroot-cvsadm-3c "cat mod1-2/mod2-2/CVS/Root" "${CVSROOT2}" - dotest multiroot-cvsadm-3d "cat mod1-2/mod2-2/CVS/Repository" "mod2-2" - dotest multiroot-cvsadm-4a "cat mod2-2/CVS/Root" "${CVSROOT2}" - dotest multiroot-cvsadm-4b "cat mod2-2/CVS/Repository" "mod2-2" - dotest multiroot-cvsadm-4c "cat mod2-2/mod1-2/CVS/Root" "${CVSROOT1}" - dotest multiroot-cvsadm-4d "cat mod2-2/mod1-2/CVS/Repository" "mod1-2" - - # - # Start testing various cvs commands. Begin with commands - # without extra arguments (e.g. "cvs update", "cvs diff", - # etc. - # - - # Do at least one command with both CVSROOTs to make sure - # that there's not some kind of unexpected dependency on the - # choice of which CVSROOT is specified on the command line. - - dotest multiroot-update-1a "${testcvs1} update" \ -"${PROG} update: Updating \. -${PROG} update: Updating mod1-1 -${PROG} update: Updating mod1-2 -${PROG} update: Updating mod1-2/mod2-2 -${PROG} update: cannot open directory ${CVSROOT1_DIRNAME}/mod2-2: No such file or directory -${PROG} update: skipping directory mod1-2/mod2-2 -${PROG} update: Updating mod2-1 -${PROG} update: cannot open directory ${CVSROOT1_DIRNAME}/mod2-1: No such file or directory -${PROG} update: skipping directory mod2-1 -${PROG} update: Updating mod2-2 -${PROG} update: cannot open directory ${CVSROOT1_DIRNAME}/mod2-2: No such file or directory -${PROG} update: skipping directory mod2-2" - - # Same deal but with -d ${CVSROOT2}. - dotest multiroot-update-1b "${testcvs2} update" \ -"${PROG} update: Updating \. -${PROG} update: Updating mod1-1 -${PROG} update: cannot open directory ${CVSROOT2_DIRNAME}/mod1-1: No such file or directory -${PROG} update: skipping directory mod1-1 -${PROG} update: Updating mod1-2 -${PROG} update: cannot open directory ${CVSROOT2_DIRNAME}/mod1-2: No such file or directory -${PROG} update: skipping directory mod1-2 -${PROG} update: Updating mod2-1 -${PROG} update: Updating mod2-2 -${PROG} update: Updating mod2-2/mod1-2 -${PROG} update: cannot open directory ${CVSROOT2_DIRNAME}/mod1-2: No such file or directory -${PROG} update: skipping directory mod2-2/mod1-2" - - # modify all files and do a diff - - echo bobby >> mod1-1/file1-1 - echo brown >> mod1-2/file1-2 - echo goes >> mod2-1/file2-1 - echo down >> mod2-2/file2-2 - - dotest_fail multiroot-diff-1 "${testcvs} diff" \ -"${PROG} diff: Diffing \. -${PROG} diff: Diffing mod1-1 -Index: mod1-1/file1-1 -=================================================================== -RCS file: ${TESTDIR}/root1/mod1-1/file1-1,v -retrieving revision 1\.1 -diff -r1\.1 file1-1 -1a2 -> bobby -${PROG} diff: Diffing mod1-2 -Index: mod1-2/file1-2 -=================================================================== -RCS file: ${TESTDIR}/root1/mod1-2/file1-2,v -retrieving revision 1\.1 -diff -r1\.1 file1-2 -1a2 -> brown -${PROG} diff: Diffing mod2-2/mod1-2 -${PROG} diff: Diffing mod1-2/mod2-2 -${PROG} diff: Diffing mod2-1 -Index: mod2-1/file2-1 -=================================================================== -RCS file: ${TESTDIR}/root2/mod2-1/file2-1,v -retrieving revision 1\.1 -diff -r1\.1 file2-1 -1a2 -> goes -${PROG} diff: Diffing mod2-2 -Index: mod2-2/file2-2 -=================================================================== -RCS file: ${TESTDIR}/root2/mod2-2/file2-2,v -retrieving revision 1\.1 -diff -r1\.1 file2-2 -1a2 -> down" \ -"${PROG} diff: Diffing \. -${PROG} diff: Diffing mod1-1 -Index: mod1-1/file1-1 -=================================================================== -RCS file: ${TESTDIR}/root1/mod1-1/file1-1,v -retrieving revision 1\.1 -diff -r1\.1 file1-1 -1a2 -> bobby -${PROG} diff: Diffing mod1-2 -Index: mod1-2/file1-2 -=================================================================== -RCS file: ${TESTDIR}/root1/mod1-2/file1-2,v -retrieving revision 1\.1 -diff -r1\.1 file1-2 -1a2 -> brown -${PROG} diff: Diffing mod2-2 -${PROG} diff: Diffing mod2-2/mod1-2 -${PROG} diff: Diffing mod1-2 -${PROG} diff: Diffing mod1-2/mod2-2 -${PROG} diff: Diffing mod2-1 -Index: mod2-1/file2-1 -=================================================================== -RCS file: ${TESTDIR}/root2/mod2-1/file2-1,v -retrieving revision 1\.1 -diff -r1\.1 file2-1 -1a2 -> goes -${PROG} diff: Diffing mod2-2 -Index: mod2-2/file2-2 -=================================================================== -RCS file: ${TESTDIR}/root2/mod2-2/file2-2,v -retrieving revision 1\.1 -diff -r1\.1 file2-2 -1a2 -> down" - - dotest multiroot-commit-1 "${testcvs} commit -m actually" \ -"${PROG} [a-z]*: Examining \. -${PROG} [a-z]*: Examining mod1-1 -${PROG} [a-z]*: Examining mod1-2 -${PROG} [a-z]*: Examining mod2-2/mod1-2 -Checking in mod1-1/file1-1; -${TESTDIR}/root1/mod1-1/file1-1,v <-- file1-1 -new revision: 1.2; previous revision: 1.1 -done -Checking in mod1-2/file1-2; -${TESTDIR}/root1/mod1-2/file1-2,v <-- file1-2 -new revision: 1.2; previous revision: 1.1 -done -${PROG} [a-z]*: Examining mod1-2/mod2-2 -${PROG} [a-z]*: Examining mod2-1 -${PROG} [a-z]*: Examining mod2-2 -Checking in mod2-1/file2-1; -${TESTDIR}/root2/mod2-1/file2-1,v <-- file2-1 -new revision: 1.2; previous revision: 1.1 -done -Checking in mod2-2/file2-2; -${TESTDIR}/root2/mod2-2/file2-2,v <-- file2-2 -new revision: 1.2; previous revision: 1.1 -done" - - dotest multiroot-update-2 "${testcvs} update" \ -"${PROG} update: Updating \. -${PROG} [a-z]*: Updating mod1-1 -${PROG} [a-z]*: Updating mod1-2 -${PROG} [a-z]*: Updating mod2-2/mod1-2 -U mod2-2/mod1-2/file1-2 -${PROG} [a-z]*: Updating mod1-2/mod2-2 -U mod1-2/mod2-2/file2-2 -${PROG} update: Updating mod2-1 -${PROG} update: Updating mod2-2" \ -"${PROG} update: Updating \. -${PROG} update: Updating mod1-1 -${PROG} update: Updating mod1-2 -${PROG} update: Updating mod2-2 -${PROG} update: Updating mod2-2/mod1-2 -P mod2-2/mod1-2/file1-2 -${PROG} update: Updating mod1-2 -${PROG} update: Updating mod1-2/mod2-2 -P mod1-2/mod2-2/file2-2 -${PROG} update: Updating mod2-1 -${PROG} update: Updating mod2-2" - - dotest multiroot-tag-1 "${testcvs} tag cattle" \ -"${PROG} tag: Tagging \. -${PROG} tag: Tagging mod1-1 -T mod1-1/file1-1 -${PROG} tag: Tagging mod1-2 -T mod1-2/file1-2 -${PROG} tag: Tagging mod2-2/mod1-2 -${PROG} tag: Tagging mod1-2/mod2-2 -T mod1-2/mod2-2/file2-2 -${PROG} tag: Tagging mod2-1 -T mod2-1/file2-1 -${PROG} tag: Tagging mod2-2" \ -"${PROG} tag: Tagging \. -${PROG} tag: Tagging mod1-1 -T mod1-1/file1-1 -${PROG} tag: Tagging mod1-2 -T mod1-2/file1-2 -${PROG} tag: Tagging mod2-2 -${PROG} tag: Tagging mod2-2/mod1-2 -${PROG} tag: Tagging mod1-2 -${PROG} tag: Tagging mod1-2/mod2-2 -T mod1-2/mod2-2/file2-2 -${PROG} tag: Tagging mod2-1 -T mod2-1/file2-1 -${PROG} tag: Tagging mod2-2" - - echo anotherfile1-1 > mod1-1/anotherfile1-1 - echo anotherfile2-1 > mod2-1/anotherfile2-1 - echo anotherfile1-2 > mod2-2/mod1-2/anotherfile1-2 - echo anotherfile2-2 > mod1-2/mod2-2/anotherfile2-2 - - if $remote; then - cd mod1-1 - dotest multiroot-add-1ar "${testcvs} add anotherfile1-1" \ -"${PROG} add: scheduling file .anotherfile1-1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - cd ../mod2-1 - dotest multiroot-add-1br "${testcvs} add anotherfile2-1" \ -"${PROG} add: scheduling file .anotherfile2-1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - cd ../mod2-2/mod1-2 - dotest multiroot-add-1cr "${testcvs} add anotherfile1-2" \ -"${PROG} add: scheduling file .anotherfile1-2. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - cd ../../mod1-2/mod2-2 - dotest multiroot-add-1dr "${testcvs} add anotherfile2-2" \ -"${PROG} add: scheduling file .anotherfile2-2. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - cd ../.. - else - dotest multiroot-add-1 "${testcvs} add mod1-1/anotherfile1-1 mod2-1/anotherfile2-1 mod2-2/mod1-2/anotherfile1-2 mod1-2/mod2-2/anotherfile2-2" \ -"${PROG} add: scheduling file .mod1-1/anotherfile1-1. for addition -${PROG} add: scheduling file .mod2-1/anotherfile2-1. for addition -${PROG} add: scheduling file .mod2-2/mod1-2/anotherfile1-2. for addition -${PROG} add: scheduling file .mod1-2/mod2-2/anotherfile2-2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - fi - - dotest multiroot-status-1 "${testcvs} status -v" \ -"${PROG} status: Examining \. -${PROG} status: Examining mod1-1 -=================================================================== -File: anotherfile1-1 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file1-1 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2) - -${PROG} status: Examining mod1-2 -=================================================================== -File: file1-2 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2) - -${PROG} status: Examining mod2-2/mod1-2 -=================================================================== -File: anotherfile1-2 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file1-2 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2) - -${PROG} status: Examining mod1-2/mod2-2 -=================================================================== -File: anotherfile2-2 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file2-2 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2) - -${PROG} status: Examining mod2-1 -=================================================================== -File: anotherfile2-1 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file2-1 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2) - -${PROG} status: Examining mod2-2 -=================================================================== -File: file2-2 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2)" \ -"${PROG} status: Examining \. -${PROG} status: Examining mod1-1 -=================================================================== -File: anotherfile1-1 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file1-1 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2) - -${PROG} status: Examining mod1-2 -=================================================================== -File: file1-2 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2) - -${PROG} status: Examining mod2-2 -${PROG} status: Examining mod2-2/mod1-2 -=================================================================== -File: anotherfile1-2 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file1-2 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2) - -${PROG} status: Examining mod1-2 -${PROG} status: Examining mod1-2/mod2-2 -=================================================================== -File: anotherfile2-2 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file2-2 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2) - -${PROG} status: Examining mod2-1 -=================================================================== -File: anotherfile2-1 Status: Locally Added - - Working revision: New file! - Repository revision: No revision control file - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - -=================================================================== -File: file2-1 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2) - -${PROG} status: Examining mod2-2 -=================================================================== -File: file2-2 Status: Up-to-date - - Working revision: 1\.2.* - Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - cattle (revision: 1\.2)" - - dotest multiroot-commit-2 "${testcvs} commit -m reading" \ -"${PROG} [a-z]*: Examining \. -${PROG} [a-z]*: Examining mod1-1 -${PROG} [a-z]*: Examining mod1-2 -${PROG} [a-z]*: Examining mod2-2/mod1-2 -RCS file: ${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v -done -Checking in mod1-1/anotherfile1-1; -${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v <-- anotherfile1-1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v -done -Checking in mod2-2/mod1-2/anotherfile1-2; -${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v <-- anotherfile1-2 -initial revision: 1\.1 -done -${PROG} [a-z]*: Examining mod1-2/mod2-2 -${PROG} [a-z]*: Examining mod2-1 -${PROG} [a-z]*: Examining mod2-2 -RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v -done -Checking in mod1-2/mod2-2/anotherfile2-2; -${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v <-- anotherfile2-2 -initial revision: 1\.1 -done -RCS file: ${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v -done -Checking in mod2-1/anotherfile2-1; -${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v <-- anotherfile2-1 -initial revision: 1\.1 -done" - - dotest multiroot-update-3 "${testcvs} update" \ -"${PROG} update: Updating \. -${PROG} [a-z]*: Updating mod1-1 -${PROG} [a-z]*: Updating mod1-2 -U mod1-2/anotherfile1-2 -${PROG} [a-z]*: Updating mod2-2/mod1-2 -${PROG} [a-z]*: Updating mod1-2/mod2-2 -${PROG} [a-z]*: Updating mod2-1 -${PROG} [a-z]*: Updating mod2-2 -U mod2-2/anotherfile2-2" \ -"${PROG} update: Updating \. -${PROG} update: Updating mod1-1 -${PROG} update: Updating mod1-2 -U mod1-2/anotherfile1-2 -${PROG} update: Updating mod2-2 -${PROG} update: Updating mod2-2/mod1-2 -${PROG} update: Updating mod1-2 -${PROG} update: Updating mod1-2/mod2-2 -${PROG} update: Updating mod2-1 -${PROG} update: Updating mod2-2 -U mod2-2/anotherfile2-2" - - dotest multiroot-log-1 "${testcvs} log" \ -"${PROG} log: Logging \. -${PROG} log: Logging mod1-1 - -RCS file: ${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v -Working file: mod1-1/anotherfile1-1 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v -Working file: mod1-1/file1-1 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -is -============================================================================= -${PROG} log: Logging mod1-2 - -RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v -Working file: mod1-2/anotherfile1-2 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v -Working file: mod1-2/file1-2 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -is -============================================================================= -${PROG} log: Logging mod2-2/mod1-2 - -RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v -Working file: mod2-2/mod1-2/anotherfile1-2 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v -Working file: mod2-2/mod1-2/file1-2 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -is -============================================================================= -${PROG} log: Logging mod1-2/mod2-2 - -RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v -Working file: mod1-2/mod2-2/anotherfile2-2 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v -Working file: mod1-2/mod2-2/file2-2 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -anyone -============================================================================= -${PROG} log: Logging mod2-1 - -RCS file: ${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v -Working file: mod2-1/anotherfile2-1 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v -Working file: mod2-1/file2-1 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -anyone -============================================================================= -${PROG} log: Logging mod2-2 - -RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v -Working file: mod2-2/anotherfile2-2 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v -Working file: mod2-2/file2-2 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -anyone -=============================================================================" \ -"${PROG} log: Logging \. -${PROG} log: Logging mod1-1 - -RCS file: ${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v -Working file: mod1-1/anotherfile1-1 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v -Working file: mod1-1/file1-1 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -is -============================================================================= -${PROG} log: Logging mod1-2 - -RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v -Working file: mod1-2/anotherfile1-2 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v -Working file: mod1-2/file1-2 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -is -============================================================================= -${PROG} log: Logging mod2-2 -${PROG} log: Logging mod2-2/mod1-2 - -RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v -Working file: mod2-2/mod1-2/anotherfile1-2 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v -Working file: mod2-2/mod1-2/file1-2 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -is -============================================================================= -${PROG} log: Logging mod1-2 -${PROG} log: Logging mod1-2/mod2-2 - -RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v -Working file: mod1-2/mod2-2/anotherfile2-2 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v -Working file: mod1-2/mod2-2/file2-2 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -anyone -============================================================================= -${PROG} log: Logging mod2-1 - -RCS file: ${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v -Working file: mod2-1/anotherfile2-1 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v -Working file: mod2-1/file2-1 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -anyone -============================================================================= -${PROG} log: Logging mod2-2 - -RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v -Working file: mod2-2/anotherfile2-2 -head: 1\.1 -branch: -locks: strict -access list: -symbolic names: -keyword substitution: kv -total revisions: 1; selected revisions: 1 -description: ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -reading -============================================================================= - -RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v -Working file: mod2-2/file2-2 -head: 1\.2 -branch: -locks: strict -access list: -symbolic names: - cattle: 1\.2 -keyword substitution: kv -total revisions: 2; selected revisions: 2 -description: ----------------------------- -revision 1\.2 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 -actually ----------------------------- -revision 1\.1 -date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; -anyone -=============================================================================" - - - # After the simple cases, let's execute some commands which - # refer to parts of our checked-out tree (e.g. "cvs update - # mod1-1 mod2-2") - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - # clean up after ourselves - cd .. - rm -r 1 - - # clean up our repositories - rm -rf root1 root2 - ;; - - multiroot2) - # More multiroot tests. In particular, nested directories. - - CVSROOT1_DIRNAME=${TESTDIR}/root1 - CVSROOT2_DIRNAME=${TESTDIR}/root2 - CVSROOT1=`newroot $CVSROOT1_DIRNAME` - CVSROOT2=`newroot $CVSROOT2_DIRNAME` - - dotest multiroot2-1 "$testcvs -d$CVSROOT1_DIRNAME init" - dotest multiroot2-2 "$testcvs -d$CVSROOT2_DIRNAME init" - - mkdir imp-dir; cd imp-dir - echo file1 >file1 - mkdir sdir - echo sfile >sdir/sfile - mkdir sdir/ssdir - echo ssfile >sdir/ssdir/ssfile - dotest_sort multiroot2-3 \ -"${testcvs} -d ${CVSROOT1} import -m import-to-root1 dir1 vend rel" " - -N dir1/file1 -N dir1/sdir/sfile -N dir1/sdir/ssdir/ssfile -No conflicts created by this import -${PROG} import: Importing ${TESTDIR}/root1/dir1/sdir -${PROG} import: Importing ${TESTDIR}/root1/dir1/sdir/ssdir" - cd sdir - dotest_sort multiroot2-4 \ -"${testcvs} -d ${CVSROOT2} import -m import-to-root2 sdir vend2 rel2" " - -N sdir/sfile -N sdir/ssdir/ssfile -No conflicts created by this import -${PROG} import: Importing ${TESTDIR}/root2/sdir/ssdir" - cd ../.. - - mkdir 1; cd 1 - # Get TopLevelAdmin-like behavior. - dotest multiroot2-5 "${testcvs} -d ${CVSROOT1} -q co -l ." - dotest multiroot2-5 "${testcvs} -d ${CVSROOT1} -q co dir1" \ -"U dir1/file1 -U dir1/sdir/sfile -U dir1/sdir/ssdir/ssfile" - cd dir1 - dotest multiroot2-6 "${testcvs} -Q release -d sdir" "" - dotest multiroot2-7 "${testcvs} -d ${CVSROOT2} -q co sdir" \ -"U sdir/sfile -U sdir/ssdir/ssfile" - cd .. - # This has one subtle effect - it deals with Entries.Log - # so that the next test doesn't get trace messages for - # Entries.Log - dotest multiroot2-8 "${testcvs} update" \ -"${PROG} update: Updating \. -${PROG} update: Updating dir1 -${PROG} update: Updating dir1/sdir -${PROG} update: Updating dir1/sdir/ssdir" \ -"${PROG} update: Updating \. -${PROG} update: Updating dir1 -${PROG} update: Updating dir1 -${PROG} update: Updating dir1/sdir -${PROG} update: Updating dir1/sdir/ssdir" - # Two reasons we don't run this on the server: (1) the server - # also prints some trace messages, and (2) the server trace - # messages are subject to out-of-order bugs (this one is hard - # to work around). - if $remote; then :; else - dotest multiroot2-9a "${testcvs} -t update" \ -" *-> main loop with CVSROOT=${TESTDIR}/root1 -${PROG} update: Updating \. - *-> Reader_Lock(${TESTDIR}/root1) - *-> Lock_Cleanup() -${PROG} update: Updating dir1 - *-> Reader_Lock(${TESTDIR}/root1/dir1) - *-> Lock_Cleanup() - *-> main loop with CVSROOT=${TESTDIR}/root2 -${PROG} update: Updating dir1/sdir - *-> Reader_Lock(${TESTDIR}/root2/sdir) - *-> Lock_Cleanup() -${PROG} update: Updating dir1/sdir/ssdir - *-> Reader_Lock(${TESTDIR}/root2/sdir/ssdir) - *-> Lock_Cleanup() - *-> Lock_Cleanup()" - fi - - dotest multiroot2-9 "${testcvs} -q tag tag1" \ -"T dir1/file1 -T dir1/sdir/sfile -T dir1/sdir/ssdir/ssfile" - echo "change it" >>dir1/file1 - echo "change him too" >>dir1/sdir/sfile - dotest multiroot2-10 "${testcvs} -q ci -m modify" \ -"Checking in dir1/file1; -${TESTDIR}/root1/dir1/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 -done -Checking in dir1/sdir/sfile; -${TESTDIR}/root2/sdir/sfile,v <-- sfile -new revision: 1\.2; previous revision: 1\.1 -done" - dotest multiroot2-11 "${testcvs} -q tag tag2" \ -"T dir1/file1 -T dir1/sdir/sfile -T dir1/sdir/ssdir/ssfile" - dotest_fail multiroot2-12 \ -"${testcvs} -q diff -u -r tag1 -r tag2" \ -"Index: dir1/file1 -=================================================================== -RCS file: ${TESTDIR}/root1/dir1/file1,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.2 -diff -u -r1\.1\.1\.1 -r1\.2 ---- dir1/file1 ${RFCDATE} 1\.1\.1\.1 -${PLUS}${PLUS}${PLUS} dir1/file1 ${RFCDATE} 1\.2 -@@ -1 ${PLUS}1,2 @@ - file1 -${PLUS}change it -Index: dir1/sdir/sfile -=================================================================== -RCS file: ${TESTDIR}/root2/sdir/sfile,v -retrieving revision 1\.1\.1\.1 -retrieving revision 1\.2 -diff -u -r1\.1\.1\.1 -r1\.2 ---- dir1/sdir/sfile ${RFCDATE} 1\.1\.1\.1 -${PLUS}${PLUS}${PLUS} dir1/sdir/sfile ${RFCDATE} 1\.2 -@@ -1 ${PLUS}1,2 @@ - sfile -${PLUS}change him too" - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - # clean up after ourselves - cd .. - rm -r imp-dir 1 - - # clean up our repositories - rm -rf root1 root2 - ;; - - multiroot3) - # More multiroot tests. Directories are side-by-side, not nested. - # Not drastically different from multiroot but it covers somewhat - # different stuff. - - CVSROOT1=`newroot ${TESTDIR}/root1` - CVSROOT2=`newroot ${TESTDIR}/root2` - - mkdir 1; cd 1 - dotest multiroot3-1 "$testcvs -d$TESTDIR/root1 init" - dotest multiroot3-2 "${testcvs} -d ${CVSROOT1} -q co -l ." "" - mkdir dir1 - dotest multiroot3-3 "${testcvs} add dir1" \ -"Directory ${TESTDIR}/root1/dir1 added to the repository" - dotest multiroot3-4 "$testcvs -d$TESTDIR/root2 init" - rm -r CVS - dotest multiroot3-5 "${testcvs} -d ${CVSROOT2} -q co -l ." "" - mkdir dir2 - - # OK, the problem is that CVS/Entries doesn't look quite right, - # I suppose because of the "rm -r". - # For local this fixes it up. - dotest multiroot3-6 "${testcvs} -d ${CVSROOT1} -q co dir1" "" - if $remote; then - # For remote that doesn't do it. Use the quick and dirty fix. - echo "D/dir1////" >CVS/Entries - echo "D/dir2////" >>CVS/Entries - fi - - dotest multiroot3-7 "${testcvs} add dir2" \ -"Directory ${TESTDIR}/root2/dir2 added to the repository" - - touch dir1/file1 dir2/file2 - if $remote; then - # Trying to add them both in one command doesn't work, - # because add.c doesn't do multiroot (it doesn't use recurse.c). - # Furthermore, it can't deal with the parent directory - # having a different root from the child, hence the cd. - cd dir1 - dotest multiroot3-8 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - cd .. - dotest multiroot3-8a "${testcvs} add dir2/file2" \ -"${PROG} add: scheduling file .dir2/file2. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - else - dotest multiroot3-8 "${testcvs} add dir1/file1 dir2/file2" \ -"${PROG} add: scheduling file .dir1/file1. for addition -${PROG} add: scheduling file .dir2/file2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - fi - - dotest multiroot3-9 "${testcvs} -q ci -m add-them" \ -"RCS file: ${TESTDIR}/root2/dir2/file2,v -done -Checking in dir2/file2; -${TESTDIR}/root2/dir2/file2,v <-- file2 -initial revision: 1\.1 -done -RCS file: ${TESTDIR}/root1/dir1/file1,v -done -Checking in dir1/file1; -${TESTDIR}/root1/dir1/file1,v <-- file1 -initial revision: 1\.1 -done" - - # That this is an error is good - we are asking CVS to do - # something which doesn't make sense. - dotest_fail multiroot3-10 \ -"${testcvs} -q -d ${CVSROOT1} diff dir1/file1 dir2/file2" \ -"${PROG} diff: failed to create lock directory for .${TESTDIR}/root1/dir2' (${TESTDIR}/root1/dir2/#cvs.lock): No such file or directory -${PROG} diff: failed to obtain dir lock in repository .${TESTDIR}/root1/dir2' -${PROG} \[diff aborted\]: read lock failed - giving up" - - # This one is supposed to work. - dotest multiroot3-11 "${testcvs} -q diff dir1/file1 dir2/file2" "" - - # make sure we can't access across repositories - mkdir 1a - cd 1a - dotest_fail multiroot3-12 \ -"$testcvs -d $CVSROOT1 -q co ../root2/dir2" \ -"$PROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\.\./root2/dir2'\." \ -"$PROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\.\./root2/dir2'\. -$PROG \[checkout aborted\]: end of file from server (consult above messages if any)" - dotest_fail multiroot3-13 \ -"$testcvs -d $CVSROOT2 -q co ../root1/dir1" \ -"$PROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\.\./root1/dir1'\." \ -"$PROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\.\./root1/dir1'\. -$PROG \[checkout aborted\]: end of file from server (consult above messages if any)" - dotest_fail multiroot3-14 \ -"$testcvs -d $CVSROOT1 -q co ./../root2/dir2" \ -"$PROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root2/dir2'\." \ -"$PROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root2/dir2'\. -$PROG \[checkout aborted\]: end of file from server (consult above messages if any)" - dotest_fail multiroot3-15 \ -"$testcvs -d $CVSROOT2 -q co ./../root1/dir1" \ -"$PROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root1/dir1'\." \ -"$PROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root1/dir1'\. -$PROG \[checkout aborted\]: end of file from server (consult above messages if any)" - dotest_fail multiroot3-16 \ -"$testcvs -d $CVSROOT1 -q co -p ../root2/dir2" \ -"$PROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\.\./root2/dir2'\." \ -"$PROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\.\./root2/dir2'\. -$PROG \[checkout aborted\]: end of file from server (consult above messages if any)" - dotest_fail multiroot3-17 \ -"$testcvs -d $CVSROOT1 -q co -p ./../root1/dir1" \ -"$PROG \[checkout aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root1/dir1'\." \ -"$PROG \[server aborted\]: up-level in module reference (\`..') invalid: \`\./\.\./root1/dir1'\. -$PROG \[checkout aborted\]: end of file from server (consult above messages if any)" - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd ../.. - - rm -r 1 - rm -rf ${TESTDIR}/root1 ${TESTDIR}/root2 - unset CVSROOT1 - unset CVSROOT2 - ;; - - multiroot4) - # More multiroot tests, in particular we have two roots with - # similarly-named directories and we try to see that CVS can - # keep them separate. - - CVSROOT1=`newroot ${TESTDIR}/root1` - CVSROOT2=`newroot ${TESTDIR}/root2` - - mkdir 1; cd 1 - dotest multiroot4-1 "$testcvs -d$TESTDIR/root1 init" - dotest multiroot4-2 "${testcvs} -d ${CVSROOT1} -q co -l ." "" - mkdir dircom - dotest multiroot4-3 "${testcvs} add dircom" \ -"Directory ${TESTDIR}/root1/dircom added to the repository" - cd dircom - touch file1 - dotest multiroot4-4 "${testcvs} add file1" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest multiroot4-5 "${testcvs} -q ci -m add" \ -"RCS file: ${TESTDIR}/root1/dircom/file1,v -done -Checking in file1; -${TESTDIR}/root1/dircom/file1,v <-- file1 -initial revision: 1\.1 -done" - cd ../.. - mkdir 2; cd 2 - dotest multiroot4-6 "$testcvs -d$TESTDIR/root2 init" - dotest multiroot4-7 "${testcvs} -d ${CVSROOT2} -q co -l ." "" - mkdir dircom - dotest multiroot4-8 "${testcvs} add dircom" \ -"Directory ${TESTDIR}/root2/dircom added to the repository" - cd dircom - touch file2 - dotest multiroot4-9 "${testcvs} add file2" \ -"${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add this file permanently" - dotest multiroot4-10 "${testcvs} -q ci -m add" \ -"RCS file: ${TESTDIR}/root2/dircom/file2,v -done -Checking in file2; -${TESTDIR}/root2/dircom/file2,v <-- file2 -initial revision: 1\.1 -done" - - cd ../.. - cd 1/dircom - # This may look contrived; the real world example which inspired - # it was that a user was changing from local to remote. Cases - # like switching servers (among those mounting the same - # repository) and so on would also look the same. - mkdir sdir2 - dotest multiroot4-11 "${testcvs} -d ${CVSROOT2} add sdir2" \ -"Directory ${TESTDIR}/root2/dircom/sdir2 added to the repository" - - dotest multiroot4-12 "${testcvs} -q update" "" - cd .. - dotest multiroot4-13 "${testcvs} -q update dircom" "" - cd .. - - rm -r 1 2 - rm -rf ${TESTDIR}/root1 ${TESTDIR}/root2 - unset CVSROOT1 - unset CVSROOT2 - ;; - - rmroot) - # When the Entries/Root file is removed from an existing - # workspace, CVS should assume $CVSROOT instead - # - # Right now only checking that CVS exits normally on an - # update once CVS/Root is deleted - # - # There was a time when this would core dump when run in - # client/server mode - - mkdir 1; cd 1 - dotest rmroot-setup-1 "${testcvs} -q co -l ." '' - mkdir first-dir - dotest rmroot-setup-2 "${testcvs} add first-dir" \ -"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository" - cd first-dir - touch file1 file2 - dotest rmroot-setup-3 "${testcvs} add file1 file2" \ -"${PROG} add: scheduling file .file1. for addition -${PROG} add: scheduling file .file2. for addition -${PROG} add: use .${PROG} commit. to add these files permanently" - dotest rmroot-setup-4 "${testcvs} -q commit -minit" \ -"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v -done -Checking in file1; -${CVSROOT_DIRNAME}/first-dir/file1,v <-- file1 -initial revision: 1\.1 -done -RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v -done -Checking in file2; -${CVSROOT_DIRNAME}/first-dir/file2,v <-- file2 -initial revision: 1\.1 -done" - rm CVS/Root - dotest rmroot-1 "${testcvs} -q update" '' - - cd ../.. - rm -rf 1 - ;; - - reposmv) - # More tests of repositories and specifying them. - # Similar to crerepos but that test is probably getting big - # enough. - CVSROOT1=`newroot ${TESTDIR}/root1` - CVSROOT_MOVED=`newroot ${TESTDIR}/root-moved` - - dotest reposmv-setup-1 "$testcvs -d$TESTDIR/root1 init" - mkdir imp-dir; cd imp-dir - echo file1 >file1 - dotest reposmv-setup-2 \ -"${testcvs} -d ${CVSROOT1} import -m add dir1 vendor release" \ -"N dir1/file1 - -No conflicts created by this import" - cd .. - - mkdir 1; cd 1 - dotest reposmv-1 "${testcvs} -d ${CVSROOT1} -Q co dir1" "" - mv ${TESTDIR}/root1 ${TESTDIR}/root-moved - cd dir1 - - # If we didn't have a relative repository, get one now. - dotest reposmv-1a "cat CVS/Repository" \ -"${TESTDIR}/root1/dir1" "dir1" - echo dir1 >CVS/Repository - - # There were some duplicated warnings and such; only test - # for the part of the error message which makes sense. - # Bug: "skipping directory " without filename. - if $remote; then - dotest_fail reposmv-2r "${testcvs} update" \ -"Cannot access ${TESTDIR}/root1/CVSROOT -No such file or directory" - else - dotest reposmv-2 "${testcvs} update" "${DOTSTAR} -${PROG} update: ignoring CVS/Root because it specifies a non-existent repository ${TESTDIR}/root1 -${PROG} update: cannot open directory ${CVSROOT_DIRNAME}/dir1: No such file or directory -${PROG} update: skipping directory " - fi - - # CVS/Root overrides $CVSROOT - if $remote; then - CVSROOT_save=${CVSROOT} - CVSROOT=:fork:${TESTDIR}/root-moved; export CVSROOT - dotest_fail reposmv-3r "${testcvs} update" \ -"Cannot access ${TESTDIR}/root1/CVSROOT -No such file or directory" - CVSROOT=${CVSROOT_save}; export CVSROOT - else - CVSROOT_save=${CVSROOT} - CVSROOT=${TESTDIR}/root-moved; export CVSROOT - dotest reposmv-3 "${testcvs} update" \ -"${DOTSTAR} -${PROG} update: ignoring CVS/Root because it specifies a non-existent repository ${TESTDIR}/root1 -${PROG} update: Updating \. -${DOTSTAR}" - CVSROOT=${CVSROOT_save}; export CVSROOT - fi - - if $remote; then - CVSROOT_save=${CVSROOT} - CVSROOT=:fork:${TESTDIR}/root-none; export CVSROOT - dotest_fail reposmv-4 "${testcvs} update" \ -"Cannot access ${TESTDIR}/root1/CVSROOT -No such file or directory" - CVSROOT=${CVSROOT_save}; export CVSROOT - else - # CVS/Root doesn't seem to quite completely override $CVSROOT - # Bug? Not necessarily a big deal if it only affects error - # messages. - CVSROOT_save=${CVSROOT} - CVSROOT=${TESTDIR}/root-none; export CVSROOT - dotest_fail reposmv-4 "${testcvs} update" \ -"${PROG} update: in directory \.: -${PROG} update: ignoring CVS/Root because it specifies a non-existent repository ${TESTDIR}/root1 -${PROG} \[update aborted\]: ${TESTDIR}/root-none/CVSROOT: No such file or directory" - CVSROOT=${CVSROOT_save}; export CVSROOT - fi - - # -d overrides CVS/Root - # - # Oddly enough, with CVS 1.10 I think this didn't work for - # local (that is, it would appear that CVS/Root would not - # get used, but would produce an error if it didn't exist). - dotest reposmv-5 "${testcvs} -d ${CVSROOT_MOVED} update" \ -"${PROG} update: Updating \." - - # TODO: could also test various other things, like what if the - # user removes CVS/Root (which is legit). Or another set of - # tests would be if both repositories exist but we want to make - # sure that CVS is using the correct one. - - cd ../.. - rm -r imp-dir 1 - rm -rf root1 root2 - unset CVSROOT1 - ;; - - pserver) - # Test basic pserver functionality. - if $remote; then - # First set SystemAuth=no. Not really necessary, I don't - # think, but somehow it seems like the clean thing for - # the testsuite. - mkdir 1; cd 1 - dotest pserver-1 "${testcvs} -Q co CVSROOT" "" - cd CVSROOT - echo "SystemAuth=no" >config - dotest pserver-2 "${testcvs} -q ci -m config-it" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cat >${CVSROOT_DIRNAME}/CVSROOT/passwd <<EOF -testme:q6WV9d2t848B2:$username -dontroot:q6WV9d2t848B2:root -anonymous::$username -$username: -willfail: :whocares -EOF - dotest_fail pserver-3 "${testcvs} pserver" \ -"error 0 Server configuration missing --allow-root in inetd.conf" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -testme -Ay::'d -END AUTH REQUEST -EOF - - dotest_fail pserver-3a "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"error 0 ${CVSROOT_DIRNAME}XXX: no such repository -I HATE YOU" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME}XXX -testme -Ay::'d -END AUTH REQUEST -EOF - - # Confirm that not sending a newline during auth cannot constitute - # a denial-of-service attack. This assumes that PATH_MAX is less - # than 65536 bytes. If PATH_MAX is larger than 65535 bytes, this - # test could hang indefinitely. - ${AWK} 'BEGIN { printf "0123456789abcdef" }' </dev/null >garbageseg - echo "BEGIN AUTH REQUEST" >garbageinput - i=0 - while test $i -lt 64; do - cat <garbageseg >>garbageseg2 - i=`expr $i + 1` - done - i=0 - while test $i -lt 64; do - cat <garbageseg2 >>garbageinput - i=`expr $i + 1` - done - dotest_fail pserver-auth-no-dos \ -"${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${PROG} \\[pserver aborted\\]: Maximum line length exceeded during authentication\." <garbageinput - unset i - rm garbageseg garbageseg2 garbageinput - - # Sending the Root and noop before waiting for the - # "I LOVE YOU" is bogus, but hopefully we can get - # away with it. - dotest pserver-4 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU -ok" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -testme -Ay::'d -END AUTH REQUEST -Root ${CVSROOT_DIRNAME} -noop -EOF - - # The "no such system user" error is occurring on at least one of - # our BSD 2.0.2 nightly test platforms. - dotest_fail pserver-4.2 \ -"${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"error 0: root not allowed" \ -"E Fatal error, aborting\. -error 0 root: no such system user" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -dontroot -Ay::'d -END AUTH REQUEST -EOF - - dotest pserver-5 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU -E Protocol error: Root says \"${TESTDIR}/1\" but pserver says \"${CVSROOT_DIRNAME}\" -error " <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -testme -Ay::'d -END AUTH REQUEST -Root ${TESTDIR}/1 -noop -EOF - - dotest pserver-5a "$testcvs --allow-root=$CVSROOT_DIRNAME pserver" \ -"$DOTSTAR LOVE YOU -E init may not be run remotely -error " <<EOF -BEGIN AUTH REQUEST -$CVSROOT_DIRNAME -testme -Ay::'d -END AUTH REQUEST -init $TESTDIR/2 -EOF - dotest_fail pserver-5b "test -d $TESTDIR/2" - - dotest_fail pserver-6 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"I HATE YOU" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -testme -Ay::'d^b?hd -END AUTH REQUEST -EOF - - dotest_fail pserver-7 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"I HATE YOU" <<EOF -BEGIN VERIFICATION REQUEST -${CVSROOT_DIRNAME} -testme -Ay::'d^b?hd -END VERIFICATION REQUEST -EOF - - dotest pserver-8 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU" <<EOF -BEGIN VERIFICATION REQUEST -${CVSROOT_DIRNAME} -testme -Ay::'d -END VERIFICATION REQUEST -EOF - -# Tests pserver-9 through pserver-13 are about empty passwords - - # Test empty password (both sides) for aliased user - dotest pserver-9 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -anonymous -A -END AUTH REQUEST -EOF - - # Test empty password (server side only) for aliased user - dotest pserver-10 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -anonymous -Aanythingwouldworkhereittrulydoesnotmatter -END AUTH REQUEST -EOF - - # Test empty (both sides) password for non-aliased user - dotest pserver-11 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -${username} -A -END AUTH REQUEST -EOF - - # Test empty (server side only) password for non-aliased user - dotest pserver-12 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -${username} -Anypasswordwouldworkwhynotthisonethen -END AUTH REQUEST -EOF - - # Test failure of whitespace password - dotest_fail pserver-13 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} HATE YOU" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -willfail -Amquiteunabletocomeupwithinterestingpasswordsanymore -END AUTH REQUEST -EOF - - # The following tests are for read-only access - - # Check that readers can only read, everyone else can write - - cat >${CVSROOT_DIRNAME}/CVSROOT/readers <<EOF -anonymous -EOF - - dotest pserver-14 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU -M Concurrent Versions System (CVS) .* -ok" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -anonymous -Ay::'d -END AUTH REQUEST -Root ${CVSROOT_DIRNAME} -version -EOF - - dotest pserver-16 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU -M Concurrent Versions System (CVS) .* -ok" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -testme -Ay::'d -END AUTH REQUEST -Root ${CVSROOT_DIRNAME} -version -EOF - - dotest pserver-18 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU -M Concurrent Versions System (CVS) .* -ok" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -${username} -Ay::'d -END AUTH REQUEST -Root ${CVSROOT_DIRNAME} -version -EOF - - # Check that writers can write, everyone else can only read - # even if not listed in readers - - cat >${CVSROOT_DIRNAME}/CVSROOT/writers <<EOF -testme -EOF - - dotest pserver-20 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU -M Concurrent Versions System (CVS) .* -ok" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -anonymous -Ay::'d -END AUTH REQUEST -Root ${CVSROOT_DIRNAME} -version -EOF - - dotest pserver-22 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU -M Concurrent Versions System (CVS) .* -ok" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -testme -Ay::'d -END AUTH REQUEST -Root ${CVSROOT_DIRNAME} -version -EOF - - dotest pserver-24 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU -M Concurrent Versions System (CVS) .* -ok" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -${username} -Ay::'d -END AUTH REQUEST -Root ${CVSROOT_DIRNAME} -version -EOF - - # Should work the same without readers - - rm ${CVSROOT_DIRNAME}/CVSROOT/readers - - dotest pserver-26 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU -M Concurrent Versions System (CVS) .* -ok" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -anonymous -Ay::'d -END AUTH REQUEST -Root ${CVSROOT_DIRNAME} -version -EOF - - dotest pserver-28 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU -M Concurrent Versions System (CVS) .* -ok" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -testme -Ay::'d -END AUTH REQUEST -Root ${CVSROOT_DIRNAME} -version -EOF - - dotest pserver-30 "${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver" \ -"${DOTSTAR} LOVE YOU -M Concurrent Versions System (CVS) .* -ok" <<EOF -BEGIN AUTH REQUEST -${CVSROOT_DIRNAME} -${username} -Ay::'d -END AUTH REQUEST -Root ${CVSROOT_DIRNAME} -version -EOF - - # pserver used to try and print from the NULL pointer - # in this error message in this case - dotest_fail pserver-bufinit "${testcvs} pserver" \ -"${PROG} \[pserver aborted\]: bad auth protocol start: EOF" </dev/null - - # Clean up. - echo "# comments only" >config - dotest pserver-cleanup-1 "${testcvs} -q ci -m config-it" \ -"Checking in config; -${CVSROOT_DIRNAME}/CVSROOT/config,v <-- config -new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* -done -${PROG} commit: Rebuilding administrative file database" - cd ../.. - rm -r 1 - rm ${CVSROOT_DIRNAME}/CVSROOT/passwd ${CVSROOT_DIRNAME}/CVSROOT/writers - fi # skip the whole thing for local - ;; - - server) - # Some tests of the server (independent of the client). - if $remote; then - dotest server-1 "${testcvs} server" \ -"E Protocol error: Root request missing -error " <<EOF -Directory bogus -mumble/bar -update -EOF - - # Could also test for relative pathnames here (so that crerepos-6a - # and crerepos-6b can use :fork:). - dotest server-2 "$testcvs server" \ -"E init may not be run remotely -error " <<EOF -Set OTHER=variable -Set MYENV=env-value -init ${TESTDIR}/crerepos -EOF - dotest_fail server-3 "test -d $TESTDIR/crerepos/CVSROOT" - - dotest server-3a "$testcvs -d$TESTDIR/crerepos init" - - # Now some tests of gzip-file-contents (used by jCVS). - ${AWK} 'BEGIN { \ -printf "%c%c%c%c%c%c.6%c%c+I-.%c%c%c%c5%c;%c%c%c%c", \ -31, 139, 8, 64, 5, 7, 64, 3, 225, 2, 64, 198, 185, 5, 64, 64, 64}' \ - </dev/null | ${TR} '\100' '\000' >gzipped.dat - # Note that the CVS client sends "-b 1.1.1", and this - # test doesn't. But the server also defaults to that. - cat <<EOF >session.dat -Root ${TESTDIR}/crerepos -UseUnchanged -gzip-file-contents 3 -Argument -m -Argument msg -Argumentx -Argument dir1 -Argument tag1 -Argument tag2 -Directory . -${TESTDIR}/crerepos -Modified file1 -u=rw,g=r,o=r -z25 -EOF - cat gzipped.dat >>session.dat - echo import >>session.dat - dotest server-4 "${testcvs} server" \ -"M N dir1/file1 -M -M No conflicts created by this import -M -ok" <session.dat - dotest server-5 \ -"${testcvs} -q -d ${TESTDIR}/crerepos co -p dir1/file1" "test" - - # OK, here are some notify tests. - dotest server-6 "${testcvs} server" \ -"Notified \./ -${TESTDIR}/crerepos/dir1/file1 -ok" <<EOF -Root ${TESTDIR}/crerepos -Directory . -${TESTDIR}/crerepos/dir1 -Notify file1 -E Fri May 7 13:21:09 1999 GMT myhost some-work-dir EUC -noop -EOF - # Sending the second "noop" before waiting for the output - # from the first is bogus but hopefully we can get away - # with it. - dotest server-7 "${testcvs} server" \ -"Notified \./ -${TESTDIR}/crerepos/dir1/file1 -ok -Notified \./ -${TESTDIR}/crerepos/dir1/file1 -ok" <<EOF -Root ${TESTDIR}/crerepos -Directory . -${TESTDIR}/crerepos/dir1 -Notify file1 -E Fri May 7 13:21:09 1999 GMT myhost some-work-dir EUC -noop -Notify file1 -E The 57th day of Discord in the YOLD 3165 myhost some-work-dir EUC -noop -EOF - - # OK, now test a few error conditions. - # FIXCVS: should give "error" and no "Notified", like server-9 - dotest server-8 "${testcvs} server" \ -"E ${PROG} server: invalid character in editor value -Notified \./ -${TESTDIR}/crerepos/dir1/file1 -ok" <<EOF -Root ${TESTDIR}/crerepos -Directory . -${TESTDIR}/crerepos/dir1 -Notify file1 -E Setting Orange, the 52th day of Discord in the YOLD 3165 myhost some-work-dir EUC -noop -EOF - - dotest server-9 "${testcvs} server" \ -"E Protocol error; misformed Notify request -error " <<EOF -Root ${TESTDIR}/crerepos -Directory . -${TESTDIR}/crerepos/dir1 -Notify file1 -E Setting Orange+57th day of Discord myhost some-work-dir EUC -noop -EOF - - # 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... - dotest server-10 "${testcvs} server" "ok" <<EOF -Root ${TESTDIR}/crerepos -Directory . -${TESTDIR}/crerepos/dir1 -watchers -EOF - # See if "watchers" and "editors" display the right thing. - dotest server-11 "${testcvs} server" \ -"M file1 ${username} tedit tunedit tcommit -ok" <<EOF -Root ${TESTDIR}/crerepos -Directory . -${TESTDIR}/crerepos/dir1 -Entry /file1/1.1//// -watchers -EOF - dotest server-12 "${testcvs} server" \ -"M file1 ${username} The 57th day of Discord in the YOLD 3165 myhost some-work-dir -ok" <<EOF -Root ${TESTDIR}/crerepos -Directory . -${TESTDIR}/crerepos/dir1 -Entry /file1/1.1//// -editors -EOF - - # Now do an unedit. - dotest server-13 "${testcvs} server" \ -"Notified \./ -${TESTDIR}/crerepos/dir1/file1 -ok" <<EOF -Root ${TESTDIR}/crerepos -Directory . -${TESTDIR}/crerepos/dir1 -Notify file1 -U 7 May 1999 15:00 GMT myhost some-work-dir EUC -noop -EOF - - # Now try "watchers" and "editors" again. - dotest server-14 "${testcvs} server" "ok" <<EOF -Root ${TESTDIR}/crerepos -Directory . -${TESTDIR}/crerepos/dir1 -watchers -EOF - dotest server-15 "${testcvs} server" "ok" <<EOF -Root ${TESTDIR}/crerepos -Directory . -${TESTDIR}/crerepos/dir1 -editors -EOF - - # Test that the global `-l' option is ignored nonfatally. - dotest server-16 "${testcvs} server" \ -"E cvs server: WARNING: global \`-l' option ignored\. -ok" <<EOF -Global_option -l -noop -EOF - - # There used to be some exploits based on malformed Entry requests - dotest server-17 "$testcvs server" \ -"E protocol error: Malformed Entry -error " <<EOF -Root $TESTDIR/crerepos -Directory . -$TESTDIR/crerepos/dir1 -Entry X/file1/1.1//// -noop -EOF - - dotest server-18 "$testcvs server" \ -"E protocol error: Malformed Entry -error " <<EOF -Root $TESTDIR/crerepos -Directory . -$TESTDIR/crerepos/dir1 -Entry /CC/CC/CC -noop -EOF - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - rm -rf ${TESTDIR}/crerepos - rm gzipped.dat session.dat - fi # skip the whole thing for local - ;; - - server2) - # More server tests, in particular testing that various - # possible security holes are plugged. - if $remote; then - dotest server2-1 "${testcvs} server" \ -"E protocol error: directory '${CVSROOT_DIRNAME}/\.\./dir1' not within root '${CVSROOT_DIRNAME}' -error " <<EOF -Root ${CVSROOT_DIRNAME} -Directory . -${CVSROOT_DIRNAME}/../dir1 -noop -EOF - - dotest server2-2 "${testcvs} server" \ -"E protocol error: directory '${CVSROOT_DIRNAME}dir1' not within root '${CVSROOT_DIRNAME}' -error " <<EOF -Root ${CVSROOT_DIRNAME} -Directory . -${CVSROOT_DIRNAME}dir1 -noop -EOF - - dotest server2-3 "${testcvs} server" \ -"E protocol error: directory '${TESTDIR}' not within root '${CVSROOT_DIRNAME}' -error " <<EOF -Root ${CVSROOT_DIRNAME} -Directory . -${TESTDIR} -noop -EOF - - # 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. - dotest server2-4 "${testcvs} server" \ -"E protocol error: directory 'foo/bar' not within current directory -error " <<EOF -Root ${CVSROOT_DIRNAME} -Directory . -${CVSROOT_DIRNAME} -Unchanged foo/bar -noop -EOF - dotest server2-5 \ -"$testcvs --allow-root=$CVSROOT_DIRNAME.bad server" \ -"E Bad root $CVSROOT_DIRNAME -error " <<EOF -Root $CVSROOT_DIRNAME -noop -EOF - dotest server2-6 \ -"$testcvs --allow-root=$CVSROOT_DIRNAME server" \ -"ok" <<EOF -Root $CVSROOT_DIRNAME -noop -EOF - fi - ;; - - - - server3) - # Test that various checks on the Root request generate the correct - # error messages. - if $remote; then - # As a control, a valid request. - dotest server3-1 "$testcvs server" 'ok' <<EOF -Root $CVSROOT_DIRNAME -Directory . -$CVSROOT_DIRNAME -Unchanged foo -noop -EOF - - dotest server3-2 "$testcvs server" \ -"E Root somewhere/over/the/rainbow must be an absolute pathname -error " <<EOF -Root somewhere/over/the/rainbow -noop -EOF - - dotest server3-3 "$testcvs server" \ -"E Protocol error: Duplicate Root request, for $CVSROOT_DIRNAME -error " <<EOF -Root $CVSROOT_DIRNAME -Root $CVSROOT_DIRNAME -noop -EOF - - dotest server3-4 "$testcvs server" \ -"E Protocol error: Duplicate Root request, for $CVSROOT_DIRNAME -error " <<EOF -Root $CVSROOT_DIRNAME -Root $CVSROOT_DIRNAME -Directory . -$CVSROOT_DIRNAME -Unchanged foo -noop -EOF - - # These cascading errors seem odd, but the client should have hung - # up after the first. - dotest server3-5 "$testcvs server" \ -"E Root somewhere/over/the/rainbow must be an absolute pathname -error -E Protocol error: Root request missing -error " <<EOF -Root somewhere/over/the/rainbow -Directory . -somewhere/over/the/rainbow -Unchanged foo -noop -EOF - fi - ;; - - - - client) - # Some tests of the client (independent of the server). - if $remote; then - cat >${TESTDIR}/serveme <<EOF -#!${TESTSHELL} -# This is admittedly a bit cheezy, in the sense that we make lots -# of assumptions about what the client is going to send us. -# We don't mention Repository, because current clients don't require it. -# Sending these at our own pace, rather than waiting for the client to -# make the requests, is bogus, but hopefully we can get away with it. -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "M special message" -echo "Created first-dir/" -echo "${CVSROOT_DIRNAME}/first-dir/file1" -echo "/file1/1.1///" -echo "u=rw,g=rw,o=rw" -echo "4" -echo "xyz" -echo "ok" -cat >/dev/null -EOF - # Cygwin. Pthffffffffft! - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod +x ${TESTDIR}/serveme" - else - chmod +x ${TESTDIR}/serveme - fi - save_CVS_SERVER=$CVS_SERVER - 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${DOTSTAR}" - dotest client-2 "${testcvs} co first-dir" "special message" - - cat >${TESTDIR}/serveme <<EOF -#!${TESTSHELL} -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "M merge-it" -echo "Copy-file ./" -echo "${CVSROOT_DIRNAME}/first-dir/file1" -echo "${TESTDIR}/bogus/.#file1.1.1" -echo "Merged ./" -echo "${CVSROOT_DIRNAME}/first-dir/file1" -echo "/file1/1.2///" -echo "u=rw,g=rw,o=rw" -echo "4" -echo "abd" -echo "ok" -cat >/dev/null -EOF - cd first-dir - mkdir ${TESTDIR}/bogus - # 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 director${DOTSTAR}" - cat >${TESTDIR}/serveme <<EOF -#!${TESTSHELL} -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "M merge-it" -echo "Copy-file ./" -echo "${CVSROOT_DIRNAME}/first-dir/file1" -echo ".#file1.1.1" -echo "Merged ./" -echo "${CVSROOT_DIRNAME}/first-dir/file1" -echo "/file1/1.2///" -echo "u=rw,g=rw,o=rw" -echo "4" -echo "abc" -echo "ok" -cat >/dev/null -EOF - dotest client-4 "${testcvs} update" "merge-it" - dotest client-5 "cat .#file1.1.1" "xyz" - dotest client-6 "cat CVS/Entries" "/file1/1.2/[A-Za-z0-9 :]*// -D" - dotest client-7 "cat file1" "abc" - - cat >${TESTDIR}/serveme <<EOF -#!${TESTSHELL} -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "M OK, whatever" -echo "ok" -cat >${TESTDIR}/client.tmp -EOF - chmod u=rw,go= file1 - # By specifying the time zone in local time, we don't - # know exactly how that will translate to GMT. - dotest client-8 "${testcvs} update -D 99-10-04" "OK, whatever" - # String 2 below is Cygwin again - ptoooey. - dotest client-9 "cat ${TESTDIR}/client.tmp" \ -"Root ${CVSROOT_DIRNAME} -Valid-responses [-a-zA-Z ]* -valid-requests -Argument -D -Argument [34] Oct 1999 [0-9][0-9]:00:00 -0000 -Argument -- -Directory \. -${CVSROOT_DIRNAME}/first-dir -Entry /file1/1\.2/// -Modified file1 -u=rw,g=,o= -4 -abc -update" \ -"Root ${CVSROOT_DIRNAME} -Valid-responses [-a-zA-Z ]* -valid-requests -Argument -D -Argument [34] Oct 1999 [0-9][0-9]:00:00 -0000 -Argument -- -Directory \. -${CVSROOT_DIRNAME}/first-dir -Entry /file1/1\.2/// -Modified file1 -u=rw,g=r,o=r -4 -abc -update" - - # The following test tests what was a potential client update in - # CVS versions 1.11.14 and CVS versions 1.12.6 and earlier. This - # exploit would allow a trojan server to create arbitrary files, - # anywhere the user had write permissions, even outside of the - # user's sandbox. - cat >$HOME/.bashrc <<EOF -#!$TESTSHELL -# This is where login scripts would usually be -# stored. -EOF - cat >$TESTDIR/serveme <<EOF -#!$TESTSHELL -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "Rcs-diff $HOME/" -echo "$HOME/.bashrc" -echo "/.bashrc/73.50///" -echo "u=rw,g=rw,o=rw" -echo "20" -echo "a1 1" -echo "echo 'gotcha!'" -echo "ok" -cat >/dev/null -EOF - - # If I don't run the following sleep between the above cat and - # the following calls to dotest, sometimes the serveme file isn't - # completely written yet by the time CVS tries to execute it, - # causing the shell to intermittantly report syntax errors (usually - # early EOF). There's probably a new race condition here, but this - # works. - # - # Incidentally, I can reproduce this behavior with Linux 2.4.20 and - # Bash 2.05 or Bash 2.05b. - sleep 1 - dotest_fail client-10 "$testcvs update" \ -"$PROG update: Server attempted to update a file via an invalid pathname: -$PROG \[update aborted\]: \`$HOME/.bashrc'\." - - # A second try at a client exploit. This one never actually - # failed in the past, but I thought it wouldn't hurt to add a test. - cat >$TESTDIR/serveme <<EOF -#!$TESTSHELL -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "Rcs-diff ./" -echo "$HOME/.bashrc" -echo "/.bashrc/73.50///" -echo "u=rw,g=rw,o=rw" -echo "20" -echo "a1 1" -echo "echo 'gotcha!'" -echo "ok" -cat >/dev/null -EOF - sleep 1 - dotest_fail client-11 "$testcvs update" \ -"$PROG \[update aborted\]: patch original file \./\.bashrc does not exist" - - # A third try at a client exploit. This one did used to fail like - # client-10. - cat >$TESTDIR/serveme <<EOF -#!$TESTSHELL -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "Rcs-diff ../../home/" -echo "../../.bashrc" -echo "/.bashrc/73.50///" -echo "u=rw,g=rw,o=rw" -echo "20" -echo "a1 1" -echo "echo 'gotcha!'" -echo "ok" -cat >/dev/null -EOF - sleep 1 - dotest_fail client-12 "$testcvs update" \ -"$PROG update: Server attempted to update a file via an invalid pathname: -$PROG \[update aborted\]: \`\.\./\.\./home/.bashrc'\." - - # Try the same exploit using the Created response. - cat >$TESTDIR/serveme <<EOF -#!$TESTSHELL -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "Created $HOME/" -echo "$HOME/.bashrc" -echo "/.bashrc/73.50///" -echo "u=rw,g=rw,o=rw" -echo "26" -echo "#! /bin/sh" -echo "echo 'gotcha!'" -echo "ok" -cat >/dev/null -EOF - sleep 1 - dotest_fail client-13 "$testcvs update" \ -"$PROG update: Server attempted to update a file via an invalid pathname: -$PROG \[update aborted\]: \`$HOME/.bashrc'\." - - # Now try using the Update-existing response - cat >$TESTDIR/serveme <<EOF -#!$TESTSHELL -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "Update-existing ../../home/" -echo "../../home/.bashrc" -echo "/.bashrc/73.50///" -echo "u=rw,g=rw,o=rw" -echo "26" -echo "#! /bin/sh" -echo "echo 'gotcha!'" -echo "ok" -cat >/dev/null -EOF - sleep 1 - dotest_fail client-14 "$testcvs update" \ -"$PROG update: Server attempted to update a file via an invalid pathname: -$PROG \[update aborted\]: \`\.\./\.\./home/.bashrc'\." - - # Try the same exploit using the Merged response. - cat >$TESTDIR/serveme <<EOF -#!$TESTSHELL -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "Merged $HOME/" -echo "$HOME/.bashrc" -echo "/.bashrc/73.50///" -echo "u=rw,g=rw,o=rw" -echo "26" -echo "#! /bin/sh" -echo "echo 'gotcha!'" -echo "ok" -cat >/dev/null -EOF - sleep 1 - dotest_fail client-15 "$testcvs update" \ -"$PROG update: Server attempted to update a file via an invalid pathname: -$PROG \[update aborted\]: \`$HOME/.bashrc'\." - - # Now try using the Updated response - cat >$TESTDIR/serveme <<EOF -#!$TESTSHELL -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "Updated ../../home/" -echo "../../home/.bashrc" -echo "/.bashrc/73.50///" -echo "u=rw,g=rw,o=rw" -echo "26" -echo "#! /bin/sh" -echo "echo 'gotcha!'" -echo "ok" -cat >/dev/null -EOF - sleep 1 - dotest_fail client-16 "$testcvs update" \ -"$PROG update: Server attempted to update a file via an invalid pathname: -$PROG \[update aborted\]: \`\.\./\.\./home/.bashrc'\." - - # Try the same exploit using the Copy-file response. - # As far as I know, Copy-file was never exploitable either. - cat >$TESTDIR/serveme <<EOF -#!$TESTSHELL -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "ok" -echo "Created ." -echo "./innocuous" -echo "/innocuous/73.50///" -echo "u=rw,g=rw,o=rw" -echo "26" -echo "#! /bin/sh" -echo "echo 'gotcha!'" -echo "Copy-file ." -echo "./innocuous" -echo "$HOME/innocuous" -echo "ok" -cat >/dev/null -EOF - sleep 1 - dotest_fail client-18 "$testcvs update" \ -"$PROG \[update aborted\]: protocol error: Copy-file tried to specify directory" - - # And verify that none of the exploits was successful. - dotest client-19 "cat $HOME/.bashrc" \ -"#!$TESTSHELL -# This is where login scripts would usually be -# stored\." - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - - cd ../.. - rm -r 1 - rmdir ${TESTDIR}/bogus - rm $TESTDIR/serveme $HOME/.bashrc - CVS_SERVER=${save_CVS_SERVER}; export CVS_SERVER - fi # skip the whole thing for local - ;; - - - - client2) - # Test how the client handles error messages from the server. - if $remote; then - cat >$TESTDIR/serveme <<EOF -#!$TESTSHELL -# This is just as cheesy as the "client" tests made it out to be. -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "E Root somewhere/over/the/rainbow must be an absolute pathname" -echo "error " -echo "E Protocol error: Root request missing" -echo "error " -cat >/dev/null -EOF - # Cygwin. Pthffffffffft! - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod +x $TESTDIR/serveme" - else - chmod +x $TESTDIR/serveme - fi - save_CVS_SERVER=$CVS_SERVER - CVS_SERVER=$TESTDIR/serveme; export CVS_SERVER - mkdir client2; cd client2 - dotest_fail client2-1 "$testcvs co first-dir" \ -"Root somewhere/over/the/rainbow must be an absolute pathname" - - cat >$TESTDIR/serveme <<EOF -#!$TESTSHELL -# This is just as cheesy as the "client" tests made it out to be. -echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" -echo "E Root somewhere/over/the/rainbow must be an absolute pathname" -echo -echo "error " -echo "E Protocol error: Root request missing" -echo "error " -cat >/dev/null -EOF - # Cygwin. Pthffffffffft! - if test -n "$remotehost"; then - $CVS_RSH $remotehost "chmod +x $TESTDIR/serveme" - else - chmod +x $TESTDIR/serveme - fi - dotest_fail client2-2 "$testcvs co first-dir" \ -"Root somewhere/over/the/rainbow must be an absolute pathname -$PROG checkout: warning: unrecognized response \`' from cvs server" - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - cd .. - rm -r client2 - rm $TESTDIR/serveme - CVS_SERVER=$save_CVS_SERVER; export CVS_SERVER - fi # skip the whole thing for local - ;; - - - - dottedroot) - # Check that a CVSROOT with a "." in the name will work. - CVSROOT_save=${CVSROOT} - CVSROOT_DIRNAME_save=${CVSROOT_DIRNAME} - CVSROOT_DIRNAME=${TESTDIR}/cvs.root - CVSROOT=`newroot ${CVSROOT_DIRNAME}` - - dotest dottedroot-init-1 "$testcvs -d$CVSROOT_DIRNAME init" - mkdir dir1 - mkdir dir1/dir2 - echo version1 >dir1/dir2/file1 - cd dir1 - dotest dottedroot-1 "${testcvs} import -m '' module1 AUTHOR INITIAL" \ -"${PROG} [a-z]*: Importing ${CVSROOT_DIRNAME}/module1/dir2 -N module1/dir2/file1 - -No conflicts created by this import" - cd .. - - # This is the test that used to cause an assertion failure - # in recurse.c:do_recursion(). - dotest dottedroot-2 "${testcvs} co -rINITIAL module1" \ -"${PROG} [a-z]*: Updating module1 -${PROG} [a-z]*: Updating module1/dir2 -U module1/dir2/file1" - - # This also triggered the assertion failure above prior to 1.11.23. - dotest dottedroot-3 \ -"$testcvs -q co -prINITIAL module1/./dir2/file1" \ -'version1' - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - - rm -rf ${CVSROOT_DIRNAME} - rm -r dir1 module1 - CVSROOT_DIRNAME=${CVSROOT_DIRNAME_save} - CVSROOT=${CVSROOT_save} - ;; - - fork) - # Test that the server defaults to the correct executable in :fork: - # mode. See the note in the TODO at the end of this file about this. - # - # This test and client should be left after all other references to - # CVS_SERVER are removed from this script. - # - # The client series of tests already tests that CVS_SERVER is - # working, but that test might be better here. - if $remote; then - mkdir fork; cd fork - save_CVS_SERVER=$CVS_SERVER - unset CVS_SERVER - # So looking through $PATH for cvs won't work... - echo "echo junk" >cvs - chmod a+x cvs - save_PATH=$PATH; PATH=.:$PATH - dotest fork-1 "$testcvs -d:fork:$CVSROOT_DIRNAME version" \ -'Client: \(.*\) -Server: \1' - CVS_SERVER=${save_CVS_SERVER}; export CVS_SERVER - unset save_CVS_SERVER - PATH=$save_PATH; unset save_PATH - cd .. - - if $keep; then - echo Keeping ${TESTDIR} and exiting due to --keep - exit 0 - fi - fi - ;; - - commit-add-missing) - # Make sure that a commit fails when a `cvs add'ed file has - # been removed from the working directory. - - mkdir 1; cd 1 - module=c-a-m - echo > unused-file - dotest commit-add-missing-1 \ - "$testcvs -Q import -m. $module X Y" '' - - file=F - # Check it out and tag it. - dotest commit-add-missing-2 "$testcvs -Q co $module" '' - cd $module - dotest commit-add-missing-3 "$testcvs -Q tag -b B" '' - echo v1 > $file - dotest commit-add-missing-4 "$testcvs -Q add $file" '' - rm -f $file - dotest_fail commit-add-missing-5 "$testcvs -Q ci -m. $file" \ -"${PROG} commit: Up-to-date check failed for .$file' -${PROG} \[commit aborted\]: correct above errors first!" - - cd ../.. - rm -rf 1 - rm -rf ${CVSROOT_DIRNAME}/$module - ;; - - add-restricted) - # Verify that `sdir/CVS' may not be explicitly added. - mkdir add-restricted; cd add-restricted - - mkdir import; cd import - : > junk - dotest add-restricted-init-1 \ -"$testcvs -Q import -m. add-restricted X Y" - cd .. - - dotest add-restricted-init-2 "$testcvs -Q co add-restricted" - cd add-restricted - - # errmsg2-3 tests the specific message here. - dotest_fail add-restricted-1 "$testcvs -Q add CVS" - - mkdir sdir - dotest add-restricted-2 "$testcvs -Q add sdir" - dotest_fail add-restricted-3 "$testcvs add sdir/CVS" \ -"$PROG add: cannot add special file \`sdir/CVS'; skipping" - - if $keep; then - echo Keeping $TESTDIR and exiting due to --keep - exit 0 - fi - cd ../.. - rm -rf add-restricted $CVSROOT_DIRNAME/add-restricted - ;; - - - - commit-d) - # Check that top-level commits work when CVS/Root - # is overridden by cvs -d. - - mkdir -p 1/subdir; cd 1 - touch file1 subdir/file2 - dotest commit-d-1 "$testcvs -Q import -m. c-d-c X Y" "" - dotest commit-d-2 "$testcvs -Q co c-d-c" "" - cd c-d-c - echo change >>file1; echo another change >>subdir/file2 - # Changing working root, then override with -d - echo nosuchhost:/cvs > CVS/Root - dotest commit-d-3 "$testcvs -Q -d $CVSROOT commit -m." \ -"Checking in file1; -${CVSROOT_DIRNAME}/c-d-c/file1,v <-- file1 -new revision: 1.2; previous revision: 1.1 -done -Checking in subdir/file2; -${CVSROOT_DIRNAME}/c-d-c/subdir/file2,v <-- file2 -new revision: 1.2; previous revision: 1.1 -done" - cd ../.. - rm -rf 1 cvsroot/c-d-c - ;; - - *) - echo $what is not the name of a test -- ignored - ;; - esac - - # Sanity check sanity.sh. :) - # - # Test our exit directory so that tests that exit in an incorrect directory - # are noticed during single test runs. - # - # FIXME? - # Sparc Solaris 9 is dereferencing paths here as if /bin/pwd were - # called when /tmp is a symlink. This might be a new problem with this - # test, but since this was recently tested I think it more likely to be - # A Solaris issue. - if test "x$TESTDIR" != "x`pwd`"; then - fail "cleanup: PWD != TESTDIR (\``pwd`' != \`$TESTDIR')" - fi - - # Reset val-tags to a pristine state. - rm -f $CVSROOT_DIRNAME/CVSROOT/val-tags - - verify_tmp_empty "post $what" - -done # The big loop - -# Set up summary data for output. -skippedoutput= -warningsoutput= -extendedinfo= -if test $skipped -ne 0; then - skippedoutput="$skipped test group" - if test $skipped -ne 1; then - skippedoutput="${skippedoutput}s" - fi - skippedoutput="$skippedoutput skipped" -fi -if test $warnings -ne 0; then - warningsoutput="$warnings test" - if test $warnings -ne 1; then - warningsoutput="${warningsoutput}s" - fi - warningsoutput="$warningsoutput passed with warnings" -fi -if test -n "$skippedoutput" || test -n "$warningsoutput"; then - extendedinfo=" (" - if test -n "$skippedoutput"; then - extendedinfo="$extendedinfo$skippedoutput" - fi - if test -n "$skippedoutput" && test -n "$warningsoutput"; then - extendedinfo="$extendedinfo and " - fi - if test -n "$warningsoutput"; then - extendedinfo="$extendedinfo$warningsoutput" - fi - extendedinfo="$extendedinfo)" -fi - -echo "OK, all $passed tests passed$extendedinfo." - -# TODO: -# * Test `cvs update -d foo' (where foo does not exist). -# * Test `cvs update foo bar' (where foo and bar are both from the -# same directory in the repository). Suppose one is a branch--make -# sure that both directories get updated with the respective correct -# thing. -# * `cvs update ../foo'. Also ../../foo ./../foo foo/../../bar /foo/bar -# foo/.././../bar foo/../bar etc. -# * Test all flags in modules file. -# Test that ciprog gets run both on checkin in that directory, or a -# higher-level checkin which recurses into it. -# * Test operations on a directory that contains other directories but has -# no files of its own. -# * -t global option -# * cvs rm followed by cvs add or vice versa (with no checkin in between). -# * cvs rm twice (should be a nice error message). -# * -P option to checkout--(a) refrains from checking out new empty dirs, -# (b) prunes empty dirs already there. -# * Test that cvs -d `hostname`:${TESTDIR}/non/existent co foo -# gives an appropriate error (e.g. -# Cannot access ${TESTDIR}/non-existent/CVSROOT -# No such file or directory). -# (like basica-9, but for remote). -# * Test ability to send notifications in response to watches. (currently -# hard to test because CVS doesn't send notifications if username is the -# same). -# * Test the contents of adm files other than Root and Repository. -# Entries seems the next most important thing. -# * Test the following compatibility issues: -# - The filler fields in "D" entries in CVS/Entries get preserved -# (per cvs.texinfo). -# - Unrecognized entry types in CVS/Entries get ignored (looks like -# this needs to be documented in cvs.texinfo, but is not) -# - Test that unrecognized files in CVS directories (e.g. CVS/Foobar) -# are ignored (per cvs.texinfo). -# - Test 'cvs history' with symlinks in the path to the working directory. -# - Remove most of the CVS_SERVER stuff after a reasonable amount of time. -# The "fork" & "client" series of tests should be left. 4/2/00, CVS -# 1.11.0.1 was altered so that it would default to program_name (set from -# argv[0]) rather than "cvs", but I'd like this script to work on legacy -# versions of CVS for awhile. -# - Testsuite doesn't work with usernames over eight characters in length. -# Fix it. -# End of TODO list. - -# Exit if keep set -if $keep; then - echo "Keeping ${TESTDIR} and exiting due to -k (keep) option." - exit 0 -fi - -# Remove the test directory, but first change out of it. -cd `dirname ${TESTDIR}` -rm -rf ${TESTDIR} - -# end of sanity.sh diff --git a/contrib/cvs/src/scramble.c b/contrib/cvs/src/scramble.c deleted file mode 100644 index 487cbf4..0000000 --- a/contrib/cvs/src/scramble.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Trivially encode strings to protect them from innocent eyes (i.e., - * inadvertent password compromises, like a network administrator - * who's watching packets for legitimate reasons and accidentally sees - * the password protocol go by). - * - * This is NOT secure encryption. - * - * It would be tempting to encode the password according to username - * and repository, so that the same password would encode to a - * different string when used with different usernames and/or - * repositories. However, then users would not be able to cut and - * paste passwords around. They're not supposed to anyway, but we all - * know they will, and there's no reason to make it harder for them if - * we're not trying to provide real security anyway. - */ - -/* Set this to test as a standalone program. */ -/* #define DIAGNOSTIC */ - -#ifndef DIAGNOSTIC -#include "cvs.h" -#else /* ! DIAGNOSTIC */ -/* cvs.h won't define this for us */ -#define AUTH_CLIENT_SUPPORT -#define xmalloc malloc -/* Use "gcc -fwritable-strings". */ -#include <stdio.h> -#include <stdio.h> -#include <string.h> -#endif /* ! DIAGNOSTIC */ - -#if defined(AUTH_CLIENT_SUPPORT) || defined(AUTH_SERVER_SUPPORT) - -/* Map characters to each other randomly and symmetrically, A <--> B. - * - * We divide the ASCII character set into 3 domains: control chars (0 - * thru 31), printing chars (32 through 126), and "meta"-chars (127 - * through 255). The control chars map _to_ themselves, the printing - * chars map _among_ themselves, and the meta chars map _among_ - * themselves. Why is this thus? - * - * No character in any of these domains maps to a character in another - * domain, because I'm not sure what characters are legal in - * passwords, or what tools people are likely to use to cut and paste - * them. It seems prudent not to introduce control or meta chars, - * unless the user introduced them first. And having the control - * chars all map to themselves insures that newline and - * carriage-return are safely handled. - */ - -static unsigned char -shifts[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87, - 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105, - 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35, - 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56, - 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48, - 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223, - 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190, - 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193, - 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212, - 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246, - 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176, - 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127, - 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195, - 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152 }; - - -/* SCRAMBLE and DESCRAMBLE work like this: - * - * scramble(STR) returns SCRM, a scrambled copy of STR. SCRM[0] is a - * single letter indicating the scrambling method. As of this - * writing, the only legal method is 'A', but check the code for more - * up-to-date information. The copy will have been allocated with - * xmalloc(). - * - * descramble(SCRM) returns STR, again in its own xmalloc'd space. - * descramble() uses SCRM[0] to determine which method of unscrambling - * to use. If it does not recognize the method, it dies with error. - */ - -/* Return a xmalloc'd, scrambled version of STR. */ -char * -scramble (str) - char *str; -{ - int i; - char *s; - - /* +2 to hold the 'A' prefix that indicates which version of - scrambling this is (the first, obviously, since we only do one - kind of scrambling so far), and then the '\0' of course. */ - s = (char *) xmalloc (strlen (str) + 2); - - /* Scramble (TM) version prefix. */ - s[0] = 'A'; - strcpy (s + 1, str); - - for (i = 1; s[i]; i++) - s[i] = shifts[(unsigned char)(s[i])]; - - return s; -} - -/* Decode the string in place. */ -char * -descramble (str) - char *str; -{ - char *s; - int i; - - /* For now we can only handle one kind of scrambling. In the future - there may be other kinds, and this `if' will become a `switch'. */ - if (str[0] != 'A') -#ifndef DIAGNOSTIC - error (1, 0, "descramble: unknown scrambling method"); -#else /* DIAGNOSTIC */ - { - fprintf (stderr, "descramble: unknown scrambling method\n", str); - fflush (stderr); - exit (EXIT_FAILURE); - } -#endif /* DIAGNOSTIC */ - - /* Method `A' is symmetrical, so scramble again to decrypt. */ - s = scramble (str + 1); - - /* Shift the whole string one char to the left, pushing the unwanted - 'A' off the left end. Safe, because s is null-terminated. */ - for (i = 0; s[i]; i++) - s[i] = s[i + 1]; - - return s; -} - -#endif /* (AUTH_CLIENT_SUPPORT || AUTH_SERVER_SUPPORT) from top of file */ - -#ifdef DIAGNOSTIC -int -main () -{ - int i; - char *e, *m, biggie[256]; - - char *cleartexts[5]; - cleartexts[0] = "first"; - cleartexts[1] = "the second"; - cleartexts[2] = "this is the third"; - cleartexts[3] = "$#% !!\\3"; - cleartexts[4] = biggie; - - /* Set up the most important test string: */ - /* Can't have a real ASCII zero in the string, because we want to - use printf, so we substitute the character zero. */ - biggie[0] = '0'; - /* The rest of the string gets straight ascending ASCII. */ - for (i = 1; i < 256; i++) - biggie[i] = i; - - /* Test all the strings. */ - for (i = 0; i < 5; i++) - { - printf ("clear%d: %s\n", i, cleartexts[i]); - e = scramble (cleartexts[i]); - printf ("scram%d: %s\n", i, e); - m = descramble (e); - free (e); - printf ("clear%d: %s\n\n", i, m); - free (m); - } - - fflush (stdout); - return 0; -} -#endif /* DIAGNOSTIC */ - -/* - * ;;; The Emacs Lisp that did the dirty work ;;; - * (progn - * - * ;; Helper func. - * (defun random-elt (lst) - * (let* ((len (length lst)) - * (rnd (random len))) - * (nth rnd lst))) - * - * ;; A list of all characters under 127, each appearing once. - * (setq non-meta-chars - * (let ((i 0) - * (l nil)) - * (while (< i 127) - * (setq l (cons i l) - * i (1+ i))) - * l)) - * - * ;; A list of all characters 127 and above, each appearing once. - * (setq meta-chars - * (let ((i 127) - * (l nil)) - * (while (< i 256) - * (setq l (cons i l) - * i (1+ i))) - * l)) - * - * ;; A vector that will hold the chars in a random order. - * (setq scrambled-chars (make-vector 256 0)) - * - * ;; These characters should map to themselves. - * (let ((i 0)) - * (while (< i 32) - * (aset scrambled-chars i i) - * (setq non-meta-chars (delete i non-meta-chars) - * i (1+ i)))) - * - * ;; Assign random (but unique) values, within the non-meta chars. - * (let ((i 32)) - * (while (< i 127) - * (let ((ch (random-elt non-meta-chars))) - * (if (= 0 (aref scrambled-chars i)) - * (progn - * (aset scrambled-chars i ch) - * (aset scrambled-chars ch i) - * (setq non-meta-chars (delete ch non-meta-chars) - * non-meta-chars (delete i non-meta-chars)))) - * (setq i (1+ i))))) - * - * ;; Assign random (but unique) values, within the non-meta chars. - * (let ((i 127)) - * (while (< i 256) - * (let ((ch (random-elt meta-chars))) - * (if (= 0 (aref scrambled-chars i)) - * (progn - * (aset scrambled-chars i ch) - * (aset scrambled-chars ch i) - * (setq meta-chars (delete ch meta-chars) - * meta-chars (delete i meta-chars)))) - * (setq i (1+ i))))) - * - * ;; Now use the `scrambled-chars' vector to get your C array. - * ) - */ diff --git a/contrib/cvs/src/server.c b/contrib/cvs/src/server.c deleted file mode 100644 index cace89d..0000000 --- a/contrib/cvs/src/server.c +++ /dev/null @@ -1,6760 +0,0 @@ -/* This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -/* - * $FreeBSD$ - */ - -#include <assert.h> -#include "cvs.h" -#include "watch.h" -#include "edit.h" -#include "fileattr.h" -#include "getline.h" -#include "buffer.h" - -int server_active = 0; - -#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) -# ifdef HAVE_GSSAPI -/* This stuff isn't included solely with SERVER_SUPPORT since some of these - * functions (encryption & the like) get compiled with or without server - * support. - * - * FIXME - They should be in a different file. - */ -# include <netdb.h> -# include "xgssapi.h" -/* We use Kerberos 5 routines to map the GSSAPI credential to a user - name. */ -# include <krb5.h> - -/* We need this to wrap data. */ -static gss_ctx_id_t gcontext; - -static void gserver_authenticate_connection PROTO((void)); - -/* Whether we are already wrapping GSSAPI communication. */ -static int cvs_gssapi_wrapping; - -# ifdef ENCRYPTION -/* Whether to encrypt GSSAPI communication. We use a global variable - like this because we use the same buffer type (gssapi_wrap) to - handle both authentication and encryption, and we don't want - multiple instances of that buffer in the communication stream. */ -int cvs_gssapi_encrypt; -# endif -# endif /* HAVE_GSSAPI */ -#endif /* defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) */ - -#ifdef SERVER_SUPPORT - -#ifdef HAVE_WINSOCK_H -#include <winsock.h> -#endif - -#if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI) -#include <sys/socket.h> -#endif - -#ifdef HAVE_SYSLOG_H -# include <syslog.h> -# ifndef LOG_DAEMON /* for ancient syslogs */ -# define LOG_DAEMON 0 -# endif -#endif - -#ifdef HAVE_KERBEROS -# include <netinet/in.h> -# include <krb.h> -# ifndef HAVE_KRB_GET_ERR_TEXT -# define krb_get_err_text(status) krb_err_txt[status] -# endif - -/* Information we need if we are going to use Kerberos encryption. */ -static C_Block kblock; -static Key_schedule sched; - -#endif - -/* for select */ -#include "xselect.h" - -#ifndef O_NONBLOCK -#define O_NONBLOCK O_NDELAY -#endif - -/* EWOULDBLOCK is not defined by POSIX, but some BSD systems will - return it, rather than EAGAIN, for nonblocking writes. */ -#ifdef EWOULDBLOCK -#define blocking_error(err) ((err) == EWOULDBLOCK || (err) == EAGAIN) -#else -#define blocking_error(err) ((err) == EAGAIN) -#endif - -/* For initgroups(). */ -#if HAVE_INITGROUPS -#include <grp.h> -#endif /* HAVE_INITGROUPS */ - -# ifdef AUTH_SERVER_SUPPORT - -# ifdef HAVE_GETSPNAM -# include <shadow.h> -# endif - -/* The cvs username sent by the client, which might or might not be - the same as the system username the server eventually switches to - run as. CVS_Username gets set iff password authentication is - successful. */ -char *CVS_Username = NULL; - -/* Used to check that same repos is transmitted in pserver auth and in - later CVS protocol. Exported because root.c also uses. */ -static char *Pserver_Repos = NULL; - -/* Should we check for system usernames/passwords? Can be changed by - CVSROOT/config. */ -int system_auth = 1; - -# endif /* AUTH_SERVER_SUPPORT */ - - -/* While processing requests, this buffer accumulates data to be sent to - the client, and then once we are in do_cvs_command, we use it - for all the data to be sent. */ -static struct buffer *buf_to_net; - -/* This buffer is used to read input from the client. */ -static struct buffer *buf_from_net; - -/* - * This is where we stash stuff we are going to use. Format string - * which expects a single directory within it, starting with a slash. - */ -static char *server_temp_dir; - -/* This is the original value of server_temp_dir, before any possible - changes inserted by serve_max_dotdot. */ -static char *orig_server_temp_dir; - -/* Nonzero if we should keep the temp directory around after we exit. */ -static int dont_delete_temp; - -static void server_write_entries PROTO((void)); - -/* All server communication goes through buffer structures. Most of - the buffers are built on top of a file descriptor. This structure - is used as the closure field in a buffer. */ - -struct fd_buffer -{ - /* The file descriptor. */ - int fd; - /* Nonzero if the file descriptor is in blocking mode. */ - int blocking; -}; - -static struct buffer *fd_buffer_initialize - PROTO ((int, int, void (*) (struct buffer *))); -static int fd_buffer_input PROTO((void *, char *, int, int, int *)); -static int fd_buffer_output PROTO((void *, const char *, int, int *)); -static int fd_buffer_flush PROTO((void *)); -static int fd_buffer_block PROTO((void *, int)); -static int fd_buffer_shutdown PROTO((struct buffer *)); - -/* Initialize a buffer built on a file descriptor. FD is the file - descriptor. INPUT is nonzero if this is for input, zero if this is - for output. MEMORY is the function to call when a memory error - occurs. */ - -static struct buffer * -fd_buffer_initialize (fd, input, memory) - int fd; - int input; - void (*memory) PROTO((struct buffer *)); -{ - struct fd_buffer *n; - - n = (struct fd_buffer *) xmalloc (sizeof *n); - n->fd = fd; - n->blocking = 1; - return buf_initialize (input ? fd_buffer_input : NULL, - input ? NULL : fd_buffer_output, - input ? NULL : fd_buffer_flush, - fd_buffer_block, - fd_buffer_shutdown, - memory, - n); -} - -/* The buffer input function for a buffer built on a file descriptor. */ - -static int -fd_buffer_input (closure, data, need, size, got) - void *closure; - char *data; - int need; - int size; - int *got; -{ - struct fd_buffer *fd = (struct fd_buffer *) closure; - int nbytes; - - if (! fd->blocking) - nbytes = read (fd->fd, data, size); - else - { - /* This case is not efficient. Fortunately, I don't think it - ever actually happens. */ - nbytes = read (fd->fd, data, need == 0 ? 1 : need); - } - - if (nbytes > 0) - { - *got = nbytes; - return 0; - } - - *got = 0; - - if (nbytes == 0) - { - /* End of file. This assumes that we are using POSIX or BSD - style nonblocking I/O. On System V we will get a zero - return if there is no data, even when not at EOF. */ - return -1; - } - - /* Some error occurred. */ - - if (blocking_error (errno)) - { - /* Everything's fine, we just didn't get any data. */ - return 0; - } - - return errno; -} - -/* The buffer output function for a buffer built on a file descriptor. */ - -static int -fd_buffer_output (closure, data, have, wrote) - void *closure; - const char *data; - int have; - int *wrote; -{ - struct fd_buffer *fd = (struct fd_buffer *) closure; - - *wrote = 0; - - while (have > 0) - { - int nbytes; - - nbytes = write (fd->fd, data, have); - - if (nbytes <= 0) - { - if (! fd->blocking - && (nbytes == 0 || blocking_error (errno))) - { - /* A nonblocking write failed to write any data. Just - return. */ - return 0; - } - - /* Some sort of error occurred. */ - - if (nbytes == 0) - return EIO; - - return errno; - } - - *wrote += nbytes; - data += nbytes; - have -= nbytes; - } - - return 0; -} - -/* The buffer flush function for a buffer built on a file descriptor. */ - -/*ARGSUSED*/ -static int -fd_buffer_flush (closure) - void *closure; -{ - /* Nothing to do. File descriptors are always flushed. */ - return 0; -} - -/* The buffer block function for a buffer built on a file descriptor. */ - -static int -fd_buffer_block (closure, block) - void *closure; - int block; -{ - struct fd_buffer *fd = (struct fd_buffer *) closure; - int flags; - - flags = fcntl (fd->fd, F_GETFL, 0); - if (flags < 0) - return errno; - - if (block) - flags &= ~O_NONBLOCK; - else - flags |= O_NONBLOCK; - - if (fcntl (fd->fd, F_SETFL, flags) < 0) - return errno; - - fd->blocking = block; - - return 0; -} - -/* The buffer shutdown function for a buffer built on a file descriptor. */ - -static int -fd_buffer_shutdown (buf) - struct buffer *buf; -{ - free (buf->closure); - buf->closure = NULL; - return 0; -} - -/* Populate all of the directories between BASE_DIR and its relative - subdirectory DIR with CVSADM directories. Return 0 for success or - errno value. */ -static int create_adm_p PROTO((char *, char *)); - -static int -create_adm_p (base_dir, dir) - char *base_dir; - char *dir; -{ - char *dir_where_cvsadm_lives, *dir_to_register, *p, *tmp; - int retval, done; - FILE *f; - - if (strcmp (dir, ".") == 0) - return 0; /* nothing to do */ - - /* Allocate some space for our directory-munging string. */ - p = xmalloc (strlen (dir) + 1); - if (p == NULL) - return ENOMEM; - - dir_where_cvsadm_lives = xmalloc (strlen (base_dir) + strlen (dir) + 100); - if (dir_where_cvsadm_lives == NULL) - { - free (p); - return ENOMEM; - } - - /* Allocate some space for the temporary string in which we will - construct filenames. */ - tmp = xmalloc (strlen (base_dir) + strlen (dir) + 100); - if (tmp == NULL) - { - free (p); - free (dir_where_cvsadm_lives); - return ENOMEM; - } - - - /* We make several passes through this loop. On the first pass, - we simply create the CVSADM directory in the deepest directory. - For each subsequent pass, we try to remove the last path - element from DIR, create the CVSADM directory in the remaining - pathname, and register the subdirectory in the newly created - CVSADM directory. */ - - retval = done = 0; - - strcpy (p, dir); - strcpy (dir_where_cvsadm_lives, base_dir); - strcat (dir_where_cvsadm_lives, "/"); - strcat (dir_where_cvsadm_lives, p); - dir_to_register = NULL; - - while (1) - { - /* Create CVSADM. */ - (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM); - if ((CVS_MKDIR (tmp, 0777) < 0) && (errno != EEXIST)) - { - retval = errno; - goto finish; - } - - /* Create CVSADM_REP. */ - (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM_REP); - if (! isfile (tmp)) - { - /* Use Emptydir as the placeholder until the client sends - us the real value. This code is similar to checkout.c - (emptydir_name), but the code below returns errors - differently. */ - - char *empty; - empty = xmalloc (strlen (current_parsed_root->directory) - + sizeof (CVSROOTADM) - + sizeof (CVSNULLREPOS) - + 3); - if (! empty) - { - retval = ENOMEM; - goto finish; - } - - /* Create the directory name. */ - (void) sprintf (empty, "%s/%s/%s", current_parsed_root->directory, - CVSROOTADM, CVSNULLREPOS); - - /* Create the directory if it doesn't exist. */ - if (! isfile (empty)) - { - mode_t omask; - omask = umask (cvsumask); - if (CVS_MKDIR (empty, 0777) < 0) - { - retval = errno; - free (empty); - goto finish; - } - (void) umask (omask); - } - - f = CVS_FOPEN (tmp, "w"); - if (f == NULL) - { - retval = errno; - free (empty); - goto finish; - } - /* Write the directory name to CVSADM_REP. */ - if (fprintf (f, "%s\n", empty) < 0) - { - retval = errno; - fclose (f); - free (empty); - goto finish; - } - if (fclose (f) == EOF) - { - retval = errno; - free (empty); - goto finish; - } - - /* Clean up after ourselves. */ - free (empty); - } - - /* Create CVSADM_ENT. We open in append mode because we - don't want to clobber an existing Entries file. */ - (void) sprintf (tmp, "%s/%s", dir_where_cvsadm_lives, CVSADM_ENT); - f = CVS_FOPEN (tmp, "a"); - if (f == NULL) - { - retval = errno; - goto finish; - } - if (fclose (f) == EOF) - { - retval = errno; - goto finish; - } - - if (dir_to_register != NULL) - { - /* FIXME: Yes, this results in duplicate entries in the - Entries.Log file, but it doesn't currently matter. We - might need to change this later on to make sure that we - only write one entry. */ - - Subdir_Register ((List *) NULL, dir_where_cvsadm_lives, - dir_to_register); - } - - if (done) - break; - - dir_to_register = strrchr (p, '/'); - if (dir_to_register == NULL) - { - dir_to_register = p; - strcpy (dir_where_cvsadm_lives, base_dir); - done = 1; - } - else - { - *dir_to_register = '\0'; - dir_to_register++; - strcpy (dir_where_cvsadm_lives, base_dir); - strcat (dir_where_cvsadm_lives, "/"); - strcat (dir_where_cvsadm_lives, p); - } - } - - finish: - free (tmp); - free (dir_where_cvsadm_lives); - free (p); - return retval; -} - -/* - * Make directory DIR, including all intermediate directories if necessary. - * Returns 0 for success or errno code. - */ -static int mkdir_p PROTO((char *)); - -static int -mkdir_p (dir) - char *dir; -{ - char *p; - char *q = xmalloc (strlen (dir) + 1); - int retval; - - if (q == NULL) - return ENOMEM; - - retval = 0; - - /* - * Skip over leading slash if present. We won't bother to try to - * make '/'. - */ - p = dir + 1; - while (1) - { - while (*p != '/' && *p != '\0') - ++p; - if (*p == '/') - { - strncpy (q, dir, p - dir); - q[p - dir] = '\0'; - if (q[p - dir - 1] != '/' && CVS_MKDIR (q, 0777) < 0) - { - int saved_errno = errno; - - if (saved_errno != EEXIST - && ((saved_errno != EACCES && saved_errno != EROFS) - || !isdir (q))) - { - retval = saved_errno; - goto done; - } - } - ++p; - } - else - { - if (CVS_MKDIR (dir, 0777) < 0) - retval = errno; - goto done; - } - } - done: - free (q); - return retval; -} - -/* - * Print the error response for error code STATUS. The caller is - * reponsible for making sure we get back to the command loop without - * any further output occuring. - * Must be called only in contexts where it is OK to send output. - */ -static void -print_error (status) - int status; -{ - char *msg; - char tmpstr[80]; - - buf_output0 (buf_to_net, "error "); - msg = strerror (status); - if (msg == NULL) - { - sprintf (tmpstr, "unknown error %d", status); - msg = tmpstr; - } - buf_output0 (buf_to_net, msg); - buf_append_char (buf_to_net, '\n'); - - buf_flush (buf_to_net, 0); -} - -static int pending_error; -/* - * Malloc'd text for pending error. Each line must start with "E ". The - * last line should not end with a newline. - */ -static char *pending_error_text; - -/* If an error is pending, print it and return 1. If not, return 0. - Must be called only in contexts where it is OK to send output. */ -static int -print_pending_error () -{ - if (pending_error_text) - { - buf_output0 (buf_to_net, pending_error_text); - buf_append_char (buf_to_net, '\n'); - if (pending_error) - print_error (pending_error); - else - buf_output0 (buf_to_net, "error \n"); - - buf_flush (buf_to_net, 0); - - pending_error = 0; - free (pending_error_text); - pending_error_text = NULL; - return 1; - } - else if (pending_error) - { - print_error (pending_error); - pending_error = 0; - return 1; - } - else - return 0; -} - -/* Is an error pending? */ -#define error_pending() (pending_error || pending_error_text) - -static int alloc_pending PROTO ((size_t size)); - -/* Allocate SIZE bytes for pending_error_text and return nonzero - if we could do it. */ -static int -alloc_pending (size) - size_t size; -{ - if (error_pending ()) - /* Probably alloc_pending callers will have already checked for - this case. But we might as well handle it if they don't, I - guess. */ - return 0; - pending_error_text = xmalloc (size); - if (pending_error_text == NULL) - { - pending_error = ENOMEM; - return 0; - } - return 1; -} - -static void serve_is_modified PROTO ((char *)); - -static int supported_response PROTO ((char *)); - -static int -supported_response (name) - char *name; -{ - struct response *rs; - - for (rs = responses; rs->name != NULL; ++rs) - if (strcmp (rs->name, name) == 0) - return rs->status == rs_supported; - error (1, 0, "internal error: testing support for unknown response?"); - /* NOTREACHED */ - return 0; -} - -static void -serve_valid_responses (arg) - char *arg; -{ - char *p = arg; - char *q; - struct response *rs; - do - { - q = strchr (p, ' '); - if (q != NULL) - *q++ = '\0'; - for (rs = responses; rs->name != NULL; ++rs) - { - if (strcmp (rs->name, p) == 0) - break; - } - if (rs->name == NULL) - /* - * It is a response we have never heard of (and thus never - * will want to use). So don't worry about it. - */ - ; - else - rs->status = rs_supported; - p = q; - } while (q != NULL); - for (rs = responses; rs->name != NULL; ++rs) - { - if (rs->status == rs_essential) - { - buf_output0 (buf_to_net, "E response `"); - buf_output0 (buf_to_net, rs->name); - buf_output0 (buf_to_net, "' not supported by client\nerror \n"); - - /* FIXME: This call to buf_flush could conceivably - cause deadlock, as noted in server_cleanup. */ - buf_flush (buf_to_net, 1); - - error_exit (); - } - else if (rs->status == rs_optional) - rs->status = rs_not_supported; - } -} - -static void -serve_root (arg) - char *arg; -{ - char *env; - char *path; - - if (error_pending()) return; - - if (!isabsolute (arg)) - { - if (alloc_pending (80 + strlen (arg))) - sprintf (pending_error_text, - "E Root %s must be an absolute pathname", arg); - return; - } - - /* Sending "Root" twice is illegal. - - The other way to handle a duplicate Root requests would be as a - request to clear out all state and start over as if it was a - new connection. Doing this would cause interoperability - headaches, so it should be a different request, if there is - any reason why such a feature is needed. */ - if (current_parsed_root != NULL) - { - if (alloc_pending (80 + strlen (arg))) - sprintf (pending_error_text, - "E Protocol error: Duplicate Root request, for %s", arg); - return; - } - - /* We need to check :ext: server here, :pserver: checks happen below. */ - if (root_allow_used() && !root_allow_ok (arg) -# ifdef AUTH_SERVER_SUPPORT - && Pserver_Repos == NULL -# endif - ) - { - if (alloc_pending (80 + strlen (arg))) - sprintf (pending_error_text, - "E Bad root %s", arg); - return; - } - -#ifdef AUTH_SERVER_SUPPORT - if (Pserver_Repos != NULL) - { - if (strcmp (Pserver_Repos, arg) != 0) - { - if (alloc_pending (80 + strlen (Pserver_Repos) + strlen (arg))) - /* The explicitness is to aid people who are writing clients. - I don't see how this information could help an - attacker. */ - sprintf (pending_error_text, "\ -E Protocol error: Root says \"%s\" but pserver says \"%s\"", - arg, Pserver_Repos); - return; - } - } -#endif - - current_parsed_root = local_cvsroot (arg); - - /* For pserver, this will already have happened, and the call will do - nothing. But for rsh, we need to do it now. */ - parse_config (current_parsed_root->directory); - - /* Now is a good time to read CVSROOT/options too. */ - parseopts(current_parsed_root->directory); - - path = xmalloc (strlen (current_parsed_root->directory) - + sizeof (CVSROOTADM) - + 2); - if (path == NULL) - { - pending_error = ENOMEM; - return; - } - (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM); - if (!isaccessible (path, R_OK | X_OK)) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (path))) - sprintf (pending_error_text, "E Cannot access %s", path); - pending_error = save_errno; - } - free (path); - -#ifdef HAVE_PUTENV - env = xmalloc (strlen (CVSROOT_ENV) + strlen (current_parsed_root->directory) + 2); - if (env == NULL) - { - pending_error = ENOMEM; - return; - } - (void) sprintf (env, "%s=%s", CVSROOT_ENV, current_parsed_root->directory); - (void) putenv (env); - /* do not free env, as putenv has control of it */ -#endif -} - -static int max_dotdot_limit = 0; - -/* Is this pathname OK to recurse into when we are running as the server? - If not, call error() with a fatal error. */ -void -server_pathname_check (path) - char *path; -{ - /* An absolute pathname is almost surely a path on the *client* machine, - and is unlikely to do us any good here. It also is probably capable - of being a security hole in the anonymous readonly case. */ - if (isabsolute (path)) - /* Giving an error is actually kind of a cop-out, in the sense - that it would be nice for "cvs co -d /foo/bar/baz" to work. - A quick fix in the server would be requiring Max-dotdot of - at least one if pathnames are absolute, and then putting - /abs/foo/bar/baz in the temp dir beside the /d/d/d stuff. - A cleaner fix in the server might be to decouple the - pathnames we pass back to the client from pathnames in our - temp directory (this would also probably remove the need - for Max-dotdot). A fix in the client would have the client - turn it into "cd /foo/bar; cvs co -d baz" (more or less). - This probably has some problems with pathnames which appear - in messages. */ - error (1, 0, "absolute pathname `%s' illegal for server", path); - if (pathname_levels (path) > max_dotdot_limit) - { - /* Similar to the isabsolute case in security implications. */ - error (0, 0, "protocol error: `%s' contains more leading ..", path); - error (1, 0, "than the %d which Max-dotdot specified", - max_dotdot_limit); - } -} - -static int outside_root PROTO ((char *)); - -/* Is file or directory REPOS an absolute pathname within the - current_parsed_root->directory? If yes, return 0. If no, set pending_error - and return 1. */ -static int -outside_root (repos) - char *repos; -{ - size_t repos_len = strlen (repos); - size_t root_len = strlen (current_parsed_root->directory); - - /* isabsolute (repos) should always be true, but - this is a good security precaution regardless. -DRP - */ - if (!isabsolute (repos)) - { - if (alloc_pending (repos_len + 80)) - sprintf (pending_error_text, "\ -E protocol error: %s is not absolute", repos); - return 1; - } - - if (repos_len < root_len - || strncmp (current_parsed_root->directory, repos, root_len) != 0) - { - not_within: - if (alloc_pending (strlen (current_parsed_root->directory) - + strlen (repos) - + 80)) - sprintf (pending_error_text, "\ -E protocol error: directory '%s' not within root '%s'", - repos, current_parsed_root->directory); - return 1; - } - if (repos_len > root_len) - { - if (repos[root_len] != '/') - goto not_within; - if (pathname_levels (repos + root_len + 1) > 0) - goto not_within; - } - return 0; -} - -static int outside_dir PROTO ((char *)); - -/* Is file or directory FILE outside the current directory (that is, does - it contain '/')? If no, return 0. If yes, set pending_error - and return 1. */ -static int -outside_dir (file) - char *file; -{ - if (strchr (file, '/') != NULL) - { - if (alloc_pending (strlen (file) - + 80)) - sprintf (pending_error_text, "\ -E protocol error: directory '%s' not within current directory", - file); - return 1; - } - return 0; -} - -/* - * Add as many directories to the temp directory as the client tells us it - * will use "..", so we never try to access something outside the temp - * directory via "..". - */ -static void -serve_max_dotdot (arg) - char *arg; -{ - int lim = atoi (arg); - int i; - char *p; - - if (lim < 0 || lim > 10000) - return; - p = xmalloc (strlen (server_temp_dir) + 2 * lim + 10); - if (p == NULL) - { - pending_error = ENOMEM; - return; - } - strcpy (p, server_temp_dir); - for (i = 0; i < lim; ++i) - strcat (p, "/d"); - if (server_temp_dir != orig_server_temp_dir) - free (server_temp_dir); - server_temp_dir = p; - max_dotdot_limit = lim; -} - -static char *dir_name; - -static void -dirswitch (dir, repos) - char *dir; - char *repos; -{ - int status; - FILE *f; - size_t dir_len; - - server_write_entries (); - - if (error_pending()) return; - - /* Check for bad directory name. - - FIXME: could/should unify these checks with server_pathname_check - except they need to report errors differently. */ - if (isabsolute (dir)) - { - if (alloc_pending (80 + strlen (dir))) - sprintf (pending_error_text, - "E absolute pathname `%s' illegal for server", dir); - return; - } - if (pathname_levels (dir) > max_dotdot_limit) - { - if (alloc_pending (80 + strlen (dir))) - sprintf (pending_error_text, - "E protocol error: `%s' has too many ..", dir); - return; - } - - dir_len = strlen (dir); - - /* Check for a trailing '/'. This is not ISDIRSEP because \ in the - protocol is an ordinary character, not a directory separator (of - course, it is perhaps unwise to use it in directory names, but that - is another issue). */ - if (dir_len > 0 - && dir[dir_len - 1] == '/') - { - if (alloc_pending (80 + dir_len)) - sprintf (pending_error_text, - "E protocol error: invalid directory syntax in %s", dir); - return; - } - - if (dir_name != NULL) - free (dir_name); - - dir_name = xmalloc (strlen (server_temp_dir) + dir_len + 40); - if (dir_name == NULL) - { - pending_error = ENOMEM; - return; - } - - strcpy (dir_name, server_temp_dir); - strcat (dir_name, "/"); - strcat (dir_name, dir); - - status = mkdir_p (dir_name); - if (status != 0 - && status != EEXIST) - { - if (alloc_pending (80 + strlen (dir_name))) - sprintf (pending_error_text, "E cannot mkdir %s", dir_name); - pending_error = status; - return; - } - - /* We need to create adm directories in all path elements because - we want the server to descend them, even if the client hasn't - sent the appropriate "Argument xxx" command to match the - already-sent "Directory xxx" command. See recurse.c - (start_recursion) for a big discussion of this. */ - - status = create_adm_p (server_temp_dir, dir); - if (status != 0) - { - if (alloc_pending (80 + strlen (dir_name))) - sprintf (pending_error_text, "E cannot create_adm_p %s", dir_name); - pending_error = status; - return; - } - - if ( CVS_CHDIR (dir_name) < 0) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (dir_name))) - sprintf (pending_error_text, "E cannot change to %s", dir_name); - pending_error = save_errno; - return; - } - /* - * This is pretty much like calling Create_Admin, but Create_Admin doesn't - * report errors in the right way for us. - */ - if ((CVS_MKDIR (CVSADM, 0777) < 0) && (errno != EEXIST)) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM))) - sprintf (pending_error_text, - "E cannot mkdir %s/%s", dir_name, CVSADM); - pending_error = save_errno; - return; - } - - /* The following will overwrite the contents of CVSADM_REP. This - is the correct behavior -- mkdir_p may have written a - placeholder value to this file and we need to insert the - correct value. */ - - f = CVS_FOPEN (CVSADM_REP, "w"); - if (f == NULL) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP))) - sprintf (pending_error_text, - "E cannot open %s/%s", dir_name, CVSADM_REP); - pending_error = save_errno; - return; - } - if (fprintf (f, "%s", repos) < 0) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP))) - sprintf (pending_error_text, - "E error writing %s/%s", dir_name, CVSADM_REP); - pending_error = save_errno; - fclose (f); - return; - } - /* Non-remote CVS handles a module representing the entire tree - (e.g., an entry like ``world -a .'') by putting /. at the end - of the Repository file, so we do the same. */ - if (strcmp (dir, ".") == 0 - && current_parsed_root != NULL - && current_parsed_root->directory != NULL - && strcmp (current_parsed_root->directory, repos) == 0) - { - if (fprintf (f, "/.") < 0) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP))) - sprintf (pending_error_text, - "E error writing %s/%s", dir_name, CVSADM_REP); - pending_error = save_errno; - fclose (f); - return; - } - } - if (fprintf (f, "\n") < 0) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP))) - sprintf (pending_error_text, - "E error writing %s/%s", dir_name, CVSADM_REP); - pending_error = save_errno; - fclose (f); - return; - } - if (fclose (f) == EOF) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP))) - sprintf (pending_error_text, - "E error closing %s/%s", dir_name, CVSADM_REP); - pending_error = save_errno; - return; - } - /* We open in append mode because we don't want to clobber an - existing Entries file. */ - f = CVS_FOPEN (CVSADM_ENT, "a"); - if (f == NULL) - { - 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; - return; - } - if (fclose (f) == EOF) - { - 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; - return; - } -} - -static void -serve_repository (arg) - char *arg; -{ - if (alloc_pending (80)) - strcpy (pending_error_text, - "E Repository request is obsolete; aborted"); - return; -} - -static void -serve_directory (arg) - char *arg; -{ - int status; - char *repos; - - status = buf_read_line (buf_from_net, &repos, (int *) NULL); - if (status == 0) - { - if (!outside_root (repos)) - dirswitch (arg, repos); - free (repos); - } - else if (status == -2) - { - pending_error = ENOMEM; - } - else - { - pending_error_text = xmalloc (80 + strlen (arg)); - if (pending_error_text == NULL) - { - pending_error = ENOMEM; - } - else if (status == -1) - { - sprintf (pending_error_text, - "E end of file reading mode for %s", arg); - } - else - { - sprintf (pending_error_text, - "E error reading mode for %s", arg); - pending_error = status; - } - } -} - -static void -serve_static_directory (arg) - char *arg; -{ - FILE *f; - - if (error_pending ()) return; - - f = CVS_FOPEN (CVSADM_ENTSTAT, "w+"); - if (f == NULL) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (CVSADM_ENTSTAT))) - sprintf (pending_error_text, "E cannot open %s", CVSADM_ENTSTAT); - pending_error = save_errno; - return; - } - if (fclose (f) == EOF) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (CVSADM_ENTSTAT))) - sprintf (pending_error_text, "E cannot close %s", CVSADM_ENTSTAT); - pending_error = save_errno; - return; - } -} - -static void -serve_sticky (arg) - char *arg; -{ - FILE *f; - - if (error_pending ()) return; - - f = CVS_FOPEN (CVSADM_TAG, "w+"); - if (f == NULL) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (CVSADM_TAG))) - sprintf (pending_error_text, "E cannot open %s", CVSADM_TAG); - pending_error = save_errno; - return; - } - if (fprintf (f, "%s\n", arg) < 0) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (CVSADM_TAG))) - sprintf (pending_error_text, "E cannot write to %s", CVSADM_TAG); - pending_error = save_errno; - (void) fclose (f); - return; - } - if (fclose (f) == EOF) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (CVSADM_TAG))) - sprintf (pending_error_text, "E cannot close %s", CVSADM_TAG); - pending_error = save_errno; - return; - } -} - -/* - * Read SIZE bytes from buf_from_net, write them to FILE. - * - * Currently this isn't really used for receiving parts of a file -- - * the file is still sent over in one chunk. But if/when we get - * spiffy in-process gzip support working, perhaps the compressed - * pieces could be sent over as they're ready, if the network is fast - * enough. Or something. - */ -static void -receive_partial_file (size, file) - int size; - int file; -{ - while (size > 0) - { - int status, nread; - char *data; - - status = buf_read_data (buf_from_net, size, &data, &nread); - if (status != 0) - { - if (status == -2) - pending_error = ENOMEM; - else - { - pending_error_text = xmalloc (80); - if (pending_error_text == NULL) - pending_error = ENOMEM; - else if (status == -1) - { - sprintf (pending_error_text, - "E premature end of file from client"); - pending_error = 0; - } - else - { - sprintf (pending_error_text, - "E error reading from client"); - pending_error = status; - } - } - return; - } - - size -= nread; - - while (nread > 0) - { - int nwrote; - - nwrote = write (file, data, nread); - if (nwrote < 0) - { - int save_errno = errno; - if (alloc_pending (40)) - strcpy (pending_error_text, "E unable to write"); - pending_error = save_errno; - - /* Read and discard the file data. */ - while (size > 0) - { - int status, nread; - char *data; - - status = buf_read_data (buf_from_net, size, &data, &nread); - if (status != 0) - return; - size -= nread; - } - - return; - } - nread -= nwrote; - data += nwrote; - } - } -} - -/* Receive SIZE bytes, write to filename FILE. */ -static void -receive_file (size, file, gzipped) - int size; - char *file; - int gzipped; -{ - int fd; - char *arg = file; - - /* Write the file. */ - fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (fd < 0) - { - int save_errno = errno; - if (alloc_pending (40 + strlen (arg))) - sprintf (pending_error_text, "E cannot open %s", arg); - pending_error = save_errno; - return; - } - - if (gzipped) - { - /* Using gunzip_and_write isn't really a high-performance - approach, because it keeps the whole thing in memory - (contiguous memory, worse yet). But it seems easier to - code than the alternative (and less vulnerable to subtle - bugs). Given that this feature is mainly for - compatibility, that is the better tradeoff. */ - - int toread = size; - char *filebuf; - char *p; - - filebuf = xmalloc (size); - p = filebuf; - /* If NULL, we still want to read the data and discard it. */ - - while (toread > 0) - { - int status, nread; - char *data; - - status = buf_read_data (buf_from_net, toread, &data, &nread); - if (status != 0) - { - if (status == -2) - pending_error = ENOMEM; - else - { - pending_error_text = xmalloc (80); - if (pending_error_text == NULL) - pending_error = ENOMEM; - else if (status == -1) - { - sprintf (pending_error_text, - "E premature end of file from client"); - pending_error = 0; - } - else - { - sprintf (pending_error_text, - "E error reading from client"); - pending_error = status; - } - } - return; - } - - toread -= nread; - - if (filebuf != NULL) - { - memcpy (p, data, nread); - p += nread; - } - } - if (filebuf == NULL) - { - pending_error = ENOMEM; - goto out; - } - - if (gunzip_and_write (fd, file, (unsigned char *) filebuf, size)) - { - if (alloc_pending (80)) - sprintf (pending_error_text, - "E aborting due to compression error"); - } - free (filebuf); - } - else - receive_partial_file (size, fd); - - if (pending_error_text) - { - char *p = xrealloc (pending_error_text, - strlen (pending_error_text) + strlen (arg) + 30); - if (p) - { - pending_error_text = p; - sprintf (p + strlen (p), ", file %s", arg); - } - /* else original string is supposed to be unchanged */ - } - - out: - if (close (fd) < 0 && !error_pending ()) - { - int save_errno = errno; - if (alloc_pending (40 + strlen (arg))) - sprintf (pending_error_text, "E cannot close %s", arg); - pending_error = save_errno; - return; - } -} - -/* Kopt for the next file sent in Modified or Is-modified. */ -static char *kopt; - -/* Timestamp (Checkin-time) for next file sent in Modified or - Is-modified. */ -static int checkin_time_valid; -static time_t checkin_time; - -static void serve_modified PROTO ((char *)); - -static void -serve_modified (arg) - char *arg; -{ - int size, status; - char *size_text; - char *mode_text; - - int gzipped = 0; - - /* - * This used to return immediately if error_pending () was true. - * However, that fails, because it causes each line of the file to - * be echoed back to the client as an unrecognized command. The - * client isn't reading from the socket, so eventually both - * processes block trying to write to the other. Now, we try to - * read the file if we can. - */ - - status = buf_read_line (buf_from_net, &mode_text, (int *) NULL); - if (status != 0) - { - if (status == -2) - pending_error = ENOMEM; - else - { - pending_error_text = xmalloc (80 + strlen (arg)); - if (pending_error_text == NULL) - pending_error = ENOMEM; - else - { - if (status == -1) - sprintf (pending_error_text, - "E end of file reading mode for %s", arg); - else - { - sprintf (pending_error_text, - "E error reading mode for %s", arg); - pending_error = status; - } - } - } - return; - } - - status = buf_read_line (buf_from_net, &size_text, (int *) NULL); - if (status != 0) - { - if (status == -2) - pending_error = ENOMEM; - else - { - pending_error_text = xmalloc (80 + strlen (arg)); - if (pending_error_text == NULL) - pending_error = ENOMEM; - else - { - if (status == -1) - sprintf (pending_error_text, - "E end of file reading size for %s", arg); - else - { - sprintf (pending_error_text, - "E error reading size for %s", arg); - pending_error = status; - } - } - } - free (mode_text); - return; - } - if (size_text[0] == 'z') - { - gzipped = 1; - size = atoi (size_text + 1); - } - else - size = atoi (size_text); - free (size_text); - - if (error_pending ()) - { - /* Now that we know the size, read and discard the file data. */ - while (size > 0) - { - int status, nread; - char *data; - - status = buf_read_data (buf_from_net, size, &data, &nread); - if (status != 0) - 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 ()) - { - free (mode_text); - return; - } - } - - if (checkin_time_valid) - { - struct utimbuf t; - - memset (&t, 0, sizeof (t)); - t.modtime = t.actime = checkin_time; - if (utime (arg, &t) < 0) - { - 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; - } - - { - int status = change_mode (arg, mode_text, 0); - free (mode_text); - if (status) - { - if (alloc_pending (40 + strlen (arg))) - sprintf (pending_error_text, - "E cannot change mode for %s", arg); - pending_error = status; - return; - } - } - - /* Make sure that the Entries indicate the right kopt. We probably - could do this even in the non-kopt case and, I think, save a stat() - call in time_stamp_server. But for conservatism I'm leaving the - non-kopt case alone. */ - if (kopt != NULL) - serve_is_modified (arg); -} - - -static void -serve_enable_unchanged (arg) - char *arg; -{ -} - -struct an_entry { - struct an_entry *next; - char *entry; -}; - -static struct an_entry *entries; - -static void serve_unchanged PROTO ((char *)); - -static void -serve_unchanged (arg) - char *arg; -{ - struct an_entry *p; - char *name; - char *cp; - char *timefield; - - if (error_pending ()) return; - - if (outside_dir (arg)) - return; - - /* Rewrite entries file to have `=' in timestamp field. */ - for (p = entries; p != NULL; p = p->next) - { - name = p->entry + 1; - cp = strchr (name, '/'); - if (cp != NULL - && strlen (arg) == cp - name - && strncmp (arg, name, cp - name) == 0) - { - if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0') - { - /* We didn't find the record separator or it is followed by - * the end of the string, so just exit. - */ - if (alloc_pending (80)) - sprintf (pending_error_text, - "E Malformed Entry encountered."); - return; - } - /* If the time field is not currently empty, then one of - * serve_modified, serve_is_modified, & serve_unchanged were - * already called for this file. We would like to ignore the - * reinvocation silently or, better yet, exit with an error - * message, but we just avoid the copy-forward and overwrite the - * value from the last invocation instead. See the comment below - * for more. - */ - if (*timefield == '/') - { - /* Copy forward one character. Space was allocated for this - * already in serve_entry(). */ - cp = timefield + strlen (timefield); - cp[1] = '\0'; - while (cp > timefield) - { - *cp = cp[-1]; - --cp; - } - } - /* If *TIMEFIELD wasn't "/", we assume that it was because of - * multiple calls to Is-Modified & Unchanged by the client and - * just overwrite the value from the last call. Technically, we - * should probably either ignore calls after the first or send the - * client an error, since the client/server protocol specification - * specifies that only one call to either Is-Modified or Unchanged - * is allowed, but broken versions of WinCVS & TortoiseCVS rely on - * this behavior. - */ - if (*timefield != '+') - /* Skip this for entries with conflict markers. */ - *timefield = '='; - break; - } - } -} - -static void -serve_is_modified (arg) - char *arg; -{ - struct an_entry *p; - char *name; - char *cp; - char *timefield; - /* Have we found this file in "entries" yet. */ - int found; - - if (error_pending ()) return; - - if (outside_dir (arg)) - return; - - /* Rewrite entries file to have `M' in timestamp field. */ - found = 0; - for (p = entries; p != NULL; p = p->next) - { - name = p->entry + 1; - cp = strchr (name, '/'); - if (cp != NULL - && strlen (arg) == cp - name - && strncmp (arg, name, cp - name) == 0) - { - if (!(timefield = strchr (cp + 1, '/')) || *++timefield == '\0') - { - /* We didn't find the record separator or it is followed by - * the end of the string, so just exit. - */ - if (alloc_pending (80)) - sprintf (pending_error_text, - "E Malformed Entry encountered."); - return; - } - /* If the time field is not currently empty, then one of - * serve_modified, serve_is_modified, & serve_unchanged were - * already called for this file. We would like to ignore the - * reinvocation silently or, better yet, exit with an error - * message, but we just avoid the copy-forward and overwrite the - * value from the last invocation instead. See the comment below - * for more. - */ - if (*timefield == '/') - { - /* Copy forward one character. Space was allocated for this - * already in serve_entry(). */ - cp = timefield + strlen (timefield); - cp[1] = '\0'; - while (cp > timefield) - { - *cp = cp[-1]; - --cp; - } - } - /* If *TIMEFIELD wasn't "/", we assume that it was because of - * multiple calls to Is-Modified & Unchanged by the client and - * just overwrite the value from the last call. Technically, we - * should probably either ignore calls after the first or send the - * client an error, since the client/server protocol specification - * specifies that only one call to either Is-Modified or Unchanged - * is allowed, but broken versions of WinCVS & TortoiseCVS rely on - * this behavior. - */ - if (*timefield != '+') - /* Skip this for entries with conflict markers. */ - *timefield = 'M'; - - if (kopt != NULL) - { - if (alloc_pending (strlen (name) + 80)) - sprintf (pending_error_text, - "E protocol error: both Kopt and Entry for %s", - arg); - free (kopt); - kopt = NULL; - return; - } - found = 1; - break; - } - } - if (!found) - { - /* We got Is-modified but no Entry. Add a dummy entry. - The "D" timestamp is what makes it a dummy. */ - p = (struct an_entry *) xmalloc (sizeof (struct an_entry)); - if (p == NULL) - { - pending_error = ENOMEM; - return; - } - p->entry = xmalloc (strlen (arg) + 80); - if (p->entry == NULL) - { - pending_error = ENOMEM; - free (p); - return; - } - strcpy (p->entry, "/"); - strcat (p->entry, arg); - strcat (p->entry, "//D/"); - if (kopt != NULL) - { - strcat (p->entry, kopt); - free (kopt); - kopt = NULL; - } - strcat (p->entry, "/"); - p->next = entries; - entries = p; - } -} - -static void serve_entry PROTO ((char *)); - -static void -serve_entry (arg) - char *arg; -{ - struct an_entry *p; - char *cp; - int i = 0; - if (error_pending()) return; - - /* Verify that the entry is well-formed. This can avoid problems later. - * At the moment we only check that the Entry contains five slashes in - * approximately the correct locations since some of the code makes - * assumptions about this. - */ - cp = arg; - if (*cp == 'D') cp++; - while (i++ < 5) - { - if (!cp || *cp != '/') - { - if (alloc_pending (80)) - sprintf (pending_error_text, - "E protocol error: Malformed Entry"); - return; - } - cp = strchr (cp + 1, '/'); - } - - p = xmalloc (sizeof (struct an_entry)); - if (p == NULL) - { - pending_error = ENOMEM; - return; - } - /* Leave space for serve_unchanged to write '=' if it wants. */ - cp = xmalloc (strlen (arg) + 2); - if (cp == NULL) - { - free (p); - pending_error = ENOMEM; - return; - } - strcpy (cp, arg); - p->next = entries; - p->entry = cp; - entries = p; -} - -static void serve_kopt PROTO ((char *)); - -static void -serve_kopt (arg) - char *arg; -{ - if (error_pending ()) - return; - - if (kopt != NULL) - { - if (alloc_pending (80 + strlen (arg))) - sprintf (pending_error_text, - "E protocol error: duplicate Kopt request: %s", arg); - return; - } - - /* Do some sanity checks. In particular, that it is not too long. - This lets the rest of the code not worry so much about buffer - overrun attacks. Probably should call RCS_check_kflag here, - but that would mean changing RCS_check_kflag to handle errors - other than via exit(), fprintf(), and such. */ - if (strlen (arg) > 10) - { - if (alloc_pending (80 + strlen (arg))) - sprintf (pending_error_text, - "E protocol error: invalid Kopt request: %s", arg); - return; - } - - kopt = xmalloc (strlen (arg) + 1); - if (kopt == NULL) - { - pending_error = ENOMEM; - return; - } - strcpy (kopt, arg); -} - -static void serve_checkin_time PROTO ((char *)); - -static void -serve_checkin_time (arg) - char *arg; -{ - if (error_pending ()) - return; - - if (checkin_time_valid) - { - if (alloc_pending (80 + strlen (arg))) - sprintf (pending_error_text, - "E protocol error: duplicate Checkin-time request: %s", - arg); - return; - } - - checkin_time = get_date (arg, NULL); - if (checkin_time == (time_t)-1) - { - if (alloc_pending (80 + strlen (arg))) - sprintf (pending_error_text, "E cannot parse date %s", arg); - return; - } - checkin_time_valid = 1; -} - -static void -server_write_entries () -{ - FILE *f; - struct an_entry *p; - struct an_entry *q; - - if (entries == NULL) - return; - - f = NULL; - /* Note that we free all the entries regardless of errors. */ - if (!error_pending ()) - { - /* We open in append mode because we don't want to clobber an - existing Entries file. If we are checking out a module - which explicitly lists more than one file in a particular - directory, then we will wind up calling - server_write_entries for each such file. */ - f = CVS_FOPEN (CVSADM_ENT, "a"); - if (f == NULL) - { - 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;) - { - if (!error_pending ()) - { - if (fprintf (f, "%s\n", p->entry) < 0) - { - 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); - q = p->next; - free (p); - p = q; - } - entries = NULL; - if (f != NULL && fclose (f) == EOF && !error_pending ()) - { - 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; - } -} - -struct notify_note { - /* Directory in which this notification happens. xmalloc'd*/ - char *dir; - - /* xmalloc'd. */ - char *filename; - - /* The following three all in one xmalloc'd block, pointed to by TYPE. - Each '\0' terminated. */ - /* "E" or "U". */ - char *type; - /* time+host+dir */ - char *val; - char *watches; - - struct notify_note *next; -}; - -static struct notify_note *notify_list; -/* Used while building list, to point to the last node that already exists. */ -static struct notify_note *last_node; - -static void serve_notify PROTO ((char *)); - -static void -serve_notify (arg) - char *arg; -{ - struct notify_note *new = NULL; - char *data = NULL; - int status; - - if (error_pending ()) return; - - if (outside_dir (arg)) - return; - - if (dir_name == NULL) - goto error; - - new = (struct notify_note *) xmalloc (sizeof (struct notify_note)); - if (new == NULL) - { - pending_error = ENOMEM; - return; - } - new->dir = xmalloc (strlen (dir_name) + 1); - new->filename = xmalloc (strlen (arg) + 1); - 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); - if (status != 0) - { - if (status == -2) - pending_error = ENOMEM; - else - { - pending_error_text = xmalloc (80 + strlen (arg)); - if (pending_error_text == NULL) - pending_error = ENOMEM; - else - { - if (status == -1) - sprintf (pending_error_text, - "E end of file reading notification for %s", arg); - else - { - sprintf (pending_error_text, - "E error reading notification for %s", arg); - pending_error = status; - } - } - } - free (new->filename); - free (new->dir); - free (new); - } - else - { - char *cp; - - if (!data[0]) - goto error; - - if (strchr (data, '+')) - goto error; - - new->type = data; - if (data[1] != '\t') - goto error; - data[1] = '\0'; - cp = data + 2; - new->val = cp; - cp = strchr (cp, '\t'); - if (cp == NULL) - goto error; - *cp++ = '+'; - cp = strchr (cp, '\t'); - if (cp == NULL) - goto error; - *cp++ = '+'; - cp = strchr (cp, '\t'); - if (cp == NULL) - goto error; - *cp++ = '\0'; - new->watches = cp; - /* If there is another tab, ignore everything after it, - for future expansion. */ - cp = strchr (cp, '\t'); - if (cp != NULL) - { - *cp = '\0'; - } - - new->next = NULL; - - if (last_node == NULL) - { - notify_list = new; - } - else - last_node->next = new; - last_node = new; - } - return; - error: - pending_error = 0; - if (alloc_pending (80)) - strcpy (pending_error_text, - "E Protocol error; misformed Notify request"); - if (data != NULL) - free (data); - if (new != NULL) - { - free (new->filename); - free (new->dir); - free (new); - } - return; -} - -/* Process all the Notify requests that we have stored up. Returns 0 - if successful, if not prints error message (via error()) and - returns negative value. */ -static int -server_notify () -{ - struct notify_note *p; - char *repos; - - while (notify_list != NULL) - { - if ( CVS_CHDIR (notify_list->dir) < 0) - { - error (0, errno, "cannot change to %s", notify_list->dir); - return -1; - } - repos = Name_Repository (NULL, NULL); - - lock_dir_for_write (repos); - - fileattr_startdir (repos); - - notify_do (*notify_list->type, notify_list->filename, getcaller(), - notify_list->val, notify_list->watches, repos); - - buf_output0 (buf_to_net, "Notified "); - { - char *dir = notify_list->dir + strlen (server_temp_dir) + 1; - if (dir[0] == '\0') - buf_append_char (buf_to_net, '.'); - else - buf_output0 (buf_to_net, dir); - buf_append_char (buf_to_net, '/'); - buf_append_char (buf_to_net, '\n'); - } - buf_output0 (buf_to_net, repos); - 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); - free (notify_list->dir); - free (notify_list->type); - free (notify_list); - notify_list = p; - - fileattr_write (); - fileattr_free (); - - Lock_Cleanup (); - } - - last_node = NULL; - - /* The code used to call fflush (stdout) here, but that is no - longer necessary. The data is now buffered in buf_to_net, - which will be flushed by the caller, do_cvs_command. */ - - return 0; -} - -static int argument_count; -static char **argument_vector; -static int argument_vector_size; - -static void -serve_argument (arg) - char *arg; -{ - char *p; - - if (error_pending()) return; - - if (argument_count >= 10000) - { - if (alloc_pending (80)) - sprintf (pending_error_text, - "E Protocol error: too many arguments"); - return; - } - - if (argument_vector_size <= argument_count) - { - argument_vector_size *= 2; - argument_vector = - (char **) xrealloc ((char *)argument_vector, - argument_vector_size * sizeof (char *)); - if (argument_vector == NULL) - { - pending_error = ENOMEM; - return; - } - } - p = xmalloc (strlen (arg) + 1); - if (p == NULL) - { - pending_error = ENOMEM; - return; - } - strcpy (p, arg); - argument_vector[argument_count++] = p; -} - -static void -serve_argumentx (arg) - char *arg; -{ - char *p; - - if (error_pending()) return; - - if (argument_count <= 1) - { - if (alloc_pending (80)) - sprintf (pending_error_text, - "E Protocol error: called argumentx without prior call to argument"); - return; - } - - p = argument_vector[argument_count - 1]; - p = xrealloc (p, strlen (p) + 1 + strlen (arg) + 1); - if (p == NULL) - { - pending_error = ENOMEM; - return; - } - strcat (p, "\n"); - strcat (p, arg); - argument_vector[argument_count - 1] = p; -} - -static void -serve_global_option (arg) - char *arg; -{ - if (arg[0] != '-' || arg[1] == '\0' || arg[2] != '\0') - { - error_return: - if (alloc_pending (strlen (arg) + 80)) - sprintf (pending_error_text, - "E Protocol error: bad global option %s", - arg); - return; - } - switch (arg[1]) - { - case 'l': - error(0, 0, "WARNING: global `-l' option ignored."); - break; - case 'n': - noexec = 1; - logoff = 1; - break; - case 'q': - quiet = 1; - break; - case 'r': - cvswrite = 0; - break; - case 'Q': - really_quiet = 1; - break; - case 't': - trace = 1; - break; - default: - goto error_return; - } -} - -static void -serve_set (arg) - char *arg; -{ - /* FIXME: This sends errors immediately (I think); they should be - put into pending_error. */ - variable_set (arg); -} - -#ifdef ENCRYPTION - -#ifdef HAVE_KERBEROS - -static void -serve_kerberos_encrypt (arg) - char *arg; -{ - /* All future communication with the client will be encrypted. */ - - buf_to_net = krb_encrypt_buffer_initialize (buf_to_net, 0, sched, - kblock, - buf_to_net->memory_error); - buf_from_net = krb_encrypt_buffer_initialize (buf_from_net, 1, sched, - kblock, - buf_from_net->memory_error); -} - -#endif /* HAVE_KERBEROS */ - -#ifdef HAVE_GSSAPI - -static void -serve_gssapi_encrypt (arg) - char *arg; -{ - if (cvs_gssapi_wrapping) - { - /* We're already using a gssapi_wrap buffer for stream - authentication. Flush everything we've output so far, and - turn on encryption for future data. On the input side, we - should only have unwrapped as far as the Gssapi-encrypt - command, so future unwrapping will become encrypted. */ - buf_flush (buf_to_net, 1); - cvs_gssapi_encrypt = 1; - return; - } - - /* All future communication with the client will be encrypted. */ - - cvs_gssapi_encrypt = 1; - - buf_to_net = cvs_gssapi_wrap_buffer_initialize (buf_to_net, 0, - gcontext, - buf_to_net->memory_error); - buf_from_net = cvs_gssapi_wrap_buffer_initialize (buf_from_net, 1, - gcontext, - buf_from_net->memory_error); - - cvs_gssapi_wrapping = 1; -} - -#endif /* HAVE_GSSAPI */ - -#endif /* ENCRYPTION */ - -#ifdef HAVE_GSSAPI - -static void -serve_gssapi_authenticate (arg) - char *arg; -{ - if (cvs_gssapi_wrapping) - { - /* We're already using a gssapi_wrap buffer for encryption. - That includes authentication, so we don't have to do - anything further. */ - return; - } - - buf_to_net = cvs_gssapi_wrap_buffer_initialize (buf_to_net, 0, - gcontext, - buf_to_net->memory_error); - buf_from_net = cvs_gssapi_wrap_buffer_initialize (buf_from_net, 1, - gcontext, - buf_from_net->memory_error); - - cvs_gssapi_wrapping = 1; -} - -#endif /* HAVE_GSSAPI */ - - - -#ifdef SERVER_FLOWCONTROL -/* The maximum we'll queue to the remote client before blocking. */ -# ifndef SERVER_HI_WATER -# define SERVER_HI_WATER (2 * 1024 * 1024) -# endif /* SERVER_HI_WATER */ -/* When the buffer drops to this, we restart the child */ -# ifndef SERVER_LO_WATER -# define SERVER_LO_WATER (1 * 1024 * 1024) -# endif /* SERVER_LO_WATER */ -#endif /* SERVER_FLOWCONTROL */ - - - -static void serve_questionable PROTO((char *)); - -static void -serve_questionable (arg) - char *arg; -{ - static int initted; - - if (!initted) - { - /* Pick up ignores from CVSROOTADM_IGNORE, $HOME/.cvsignore on server, - and CVSIGNORE on server. */ - ign_setup (); - initted = 1; - } - - if (dir_name == NULL) - { - buf_output0 (buf_to_net, "E Protocol error: 'Directory' missing"); - return; - } - - if (outside_dir (arg)) - return; - - if (!ign_name (arg)) - { - char *update_dir; - - buf_output (buf_to_net, "M ? ", 4); - update_dir = dir_name + strlen (server_temp_dir) + 1; - if (!(update_dir[0] == '.' && update_dir[1] == '\0')) - { - buf_output0 (buf_to_net, update_dir); - buf_output (buf_to_net, "/", 1); - } - buf_output0 (buf_to_net, arg); - buf_output (buf_to_net, "\n", 1); - } -} - - - -static struct buffer *protocol; - -/* This is the output which we are saving up to send to the server, in the - child process. We will push it through, via the `protocol' buffer, when - we have a complete line. */ -static struct buffer *saved_output; -/* Likewise, but stuff which will go to stderr. */ -static struct buffer *saved_outerr; - -static void -protocol_memory_error (buf) - struct buffer *buf; -{ - error (1, ENOMEM, "Virtual memory exhausted"); -} - -/* - * Process IDs of the subprocess, or negative if that subprocess - * does not exist. - */ -static pid_t command_pid; - -static void -outbuf_memory_error (buf) - struct buffer *buf; -{ - static const char msg[] = "E Fatal server error\n\ -error ENOMEM Virtual memory exhausted.\n"; - if (command_pid > 0) - kill (command_pid, SIGTERM); - - /* - * We have arranged things so that printing this now either will - * be legal, or the "E fatal error" line will get glommed onto the - * end of an existing "E" or "M" response. - */ - - /* If this gives an error, not much we could do. syslog() it? */ - write (STDOUT_FILENO, msg, sizeof (msg) - 1); -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_ERR, "virtual memory exhausted"); -#endif - error_exit (); -} - -static void -input_memory_error (buf) - struct buffer *buf; -{ - outbuf_memory_error (buf); -} - - - -/* If command is legal, return 1. - * Else if command is illegal and croak_on_illegal is set, then die. - * Else just return 0 to indicate that command is illegal. - */ -static int -check_command_legal_p (cmd_name) - char *cmd_name; -{ - /* Right now, only pserver notices illegal commands -- namely, - * write attempts by a read-only user. Therefore, if CVS_Username - * is not set, this just returns 1, because CVS_Username unset - * means pserver is not active. - */ -#ifdef AUTH_SERVER_SUPPORT - if (CVS_Username == NULL) - return 1; - - if (lookup_command_attribute (cmd_name) & CVS_CMD_MODIFIES_REPOSITORY) - { - /* This command has the potential to modify the repository, so - * we check if the user have permission to do that. - * - * (Only relevant for remote users -- local users can do - * whatever normal Unix file permissions allow them to do.) - * - * The decision method: - * - * If $CVSROOT/CVSADMROOT_READERS exists and user is listed - * in it, then read-only access for user. - * - * Or if $CVSROOT/CVSADMROOT_WRITERS exists and user NOT - * listed in it, then also read-only access for user. - * - * Else read-write access for user. - */ - - char *linebuf = NULL; - int num_red = 0; - size_t linebuf_len = 0; - char *fname; - size_t flen; - FILE *fp; - int found_it = 0; - - /* else */ - flen = strlen (current_parsed_root->directory) - + strlen (CVSROOTADM) - + strlen (CVSROOTADM_READERS) - + 3; - - fname = xmalloc (flen); - (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory, - CVSROOTADM, CVSROOTADM_READERS); - - fp = fopen (fname, "r"); - - if (fp == NULL) - { - if (!existence_error (errno)) - { - /* Need to deny access, so that attackers can't fool - us with some sort of denial of service attack. */ - error (0, errno, "cannot open %s", fname); - free (fname); - return 0; - } - } - else /* successfully opened readers file */ - { - while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0) - { - /* Hmmm, is it worth importing my own readline - library into CVS? It takes care of chopping - leading and trailing whitespace, "#" comments, and - newlines automatically when so requested. Would - save some code here... -kff */ - - /* Chop newline by hand, for strcmp()'s sake. */ - if (num_red > 0 && linebuf[num_red - 1] == '\n') - linebuf[num_red - 1] = '\0'; - - if (strcmp (linebuf, CVS_Username) == 0) - goto handle_illegal; - } - if (num_red < 0 && !feof (fp)) - error (0, errno, "cannot read %s", fname); - - /* If not listed specifically as a reader, then this user - has write access by default unless writers are also - specified in a file . */ - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", fname); - } - free (fname); - - /* Now check the writers file. */ - - flen = strlen (current_parsed_root->directory) - + strlen (CVSROOTADM) - + strlen (CVSROOTADM_WRITERS) - + 3; - - fname = xmalloc (flen); - (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory, - CVSROOTADM, CVSROOTADM_WRITERS); - - fp = fopen (fname, "r"); - - if (fp == NULL) - { - if (linebuf) - free (linebuf); - if (existence_error (errno)) - { - /* Writers file does not exist, so everyone is a writer, - by default. */ - free (fname); - return 1; - } - else - { - /* Need to deny access, so that attackers can't fool - us with some sort of denial of service attack. */ - error (0, errno, "cannot read %s", fname); - free (fname); - return 0; - } - } - - found_it = 0; - while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0) - { - /* Chop newline by hand, for strcmp()'s sake. */ - if (num_red > 0 && linebuf[num_red - 1] == '\n') - linebuf[num_red - 1] = '\0'; - - if (strcmp (linebuf, CVS_Username) == 0) - { - found_it = 1; - break; - } - } - if (num_red < 0 && !feof (fp)) - error (0, errno, "cannot read %s", fname); - - if (found_it) - { - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", fname); - if (linebuf) - free (linebuf); - free (fname); - return 1; - } - else /* writers file exists, but this user not listed in it */ - { - handle_illegal: - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", fname); - if (linebuf) - free (linebuf); - free (fname); - return 0; - } - } -#endif /* AUTH_SERVER_SUPPORT */ - - /* If ever reach end of this function, command must be legal. */ - return 1; -} - - - -/* Execute COMMAND in a subprocess with the approriate funky things done. */ - -static struct fd_set_wrapper { fd_set fds; } command_fds_to_drain; -#ifdef SUNOS_KLUDGE -static int max_command_fd; -#endif - -#ifdef SERVER_FLOWCONTROL -static int flowcontrol_pipe[2]; -#endif /* SERVER_FLOWCONTROL */ - - - -/* - * Set buffer FD to non-blocking I/O. Returns 0 for success or errno - * code. - */ -int -set_nonblock_fd (fd) - int fd; -{ - int flags; - - flags = fcntl (fd, F_GETFL, 0); - if (flags < 0) - return errno; - if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0) - return errno; - return 0; -} - - - -/* - * Set buffer FD to blocking I/O. Returns 0 for success or errno code. - */ -int -set_block_fd (fd) - int fd; -{ - int flags; - - flags = fcntl (fd, F_GETFL, 0); - if (flags < 0) - return errno; - if (fcntl (fd, F_SETFL, flags & ~O_NONBLOCK) < 0) - return errno; - return 0; -} - - - -static void -do_cvs_command (cmd_name, command) - char *cmd_name; - int (*command) PROTO((int argc, char **argv)); -{ - /* - * The following file descriptors are set to -1 if that file is not - * currently open. - */ - - /* Data on these pipes is a series of '\n'-terminated lines. */ - int stdout_pipe[2]; - int stderr_pipe[2]; - - /* - * Data on this pipe is a series of counted (see buf_send_counted) - * packets. Each packet must be processed atomically (i.e. not - * interleaved with data from stdout_pipe or stderr_pipe). - */ - int protocol_pipe[2]; - - int dev_null_fd = -1; - - int errs = 0; - - command_pid = -1; - stdout_pipe[0] = -1; - stdout_pipe[1] = -1; - stderr_pipe[0] = -1; - stderr_pipe[1] = -1; - protocol_pipe[0] = -1; - protocol_pipe[1] = -1; - - server_write_entries (); - - if (print_pending_error ()) - goto free_args_and_return; - - /* Global `cvs_cmd_name' is probably "server" right now -- only - serve_export() sets it to anything else. So we will use local - parameter `cmd_name' to determine if this command is legal for - this user. */ - if (!check_command_legal_p (cmd_name)) - { - buf_output0 (buf_to_net, "E "); - buf_output0 (buf_to_net, program_name); - buf_output0 (buf_to_net, " [server aborted]: \""); - buf_output0 (buf_to_net, cmd_name); - buf_output0 (buf_to_net, "\" requires write access to the repository\n\ -error \n"); - goto free_args_and_return; - } - cvs_cmd_name = cmd_name; - - (void) server_notify (); - - /* - * We use a child process which actually does the operation. This - * is so we can intercept its standard output. Even if all of CVS - * were written to go to some special routine instead of writing - * to stdout or stderr, we would still need to do the same thing - * for the RCS commands. - */ - - 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; - } - set_nonblock_fd (flowcontrol_pipe[0]); - set_nonblock_fd (flowcontrol_pipe[1]); -#endif /* SERVER_FLOWCONTROL */ - - 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; - } - - /* We shouldn't have any partial lines from cvs_output and - cvs_outerr, but we handle them here in case there is a bug. */ - /* FIXME: appending a newline, rather than using "MT" as we - do in the child process, is probably not really a very good - way to "handle" them. */ - if (! buf_empty_p (saved_output)) - { - buf_append_char (saved_output, '\n'); - buf_copy_lines (buf_to_net, saved_output, 'M'); - } - if (! buf_empty_p (saved_outerr)) - { - buf_append_char (saved_outerr, '\n'); - buf_copy_lines (buf_to_net, saved_outerr, 'E'); - } - - /* Flush out any pending data. */ - buf_flush (buf_to_net, 1); - - /* Don't use vfork; we're not going to exec(). */ - command_pid = fork (); - if (command_pid < 0) - { - buf_output0 (buf_to_net, "E fork failed\n"); - print_error (errno); - goto error_exit; - } - if (command_pid == 0) - { - int exitstatus; - - /* Since we're in the child, and the parent is going to take - care of packaging up our error messages, we can clear this - flag. */ - error_use_protocol = 0; - - protocol = fd_buffer_initialize (protocol_pipe[1], 0, - protocol_memory_error); - - /* At this point we should no longer be using buf_to_net and - buf_from_net. Instead, everything should go through - protocol. */ - if (buf_to_net != NULL) - { - buf_free (buf_to_net); - buf_to_net = NULL; - } - if (buf_from_net != NULL) - { - buf_free (buf_from_net); - buf_from_net = NULL; - } - - /* These were originally set up to use outbuf_memory_error. - Since we're now in the child, we should use the simpler - protocol_memory_error function. */ - saved_output->memory_error = protocol_memory_error; - saved_outerr->memory_error = protocol_memory_error; - - if (dup2 (dev_null_fd, STDIN_FILENO) < 0) - error (1, errno, "can't set up pipes"); - if (dup2 (stdout_pipe[1], STDOUT_FILENO) < 0) - 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]); - close_on_exec (protocol_pipe[1]); -#ifdef SERVER_FLOWCONTROL - close_on_exec (flowcontrol_pipe[0]); - close (flowcontrol_pipe[1]); -#endif /* SERVER_FLOWCONTROL */ - - /* - * Set this in .bashrc if you want to give yourself time to attach - * to the subprocess with a debugger. - */ - if (getenv ("CVS_SERVER_SLEEP")) - { - int secs = atoi (getenv ("CVS_SERVER_SLEEP")); - sleep (secs); - } - - exitstatus = (*command) (argument_count, argument_vector); - - /* Output any partial lines. If the client doesn't support - "MT", we go ahead and just tack on a newline since the - protocol doesn't support anything better. */ - if (! buf_empty_p (saved_output)) - { - buf_output0 (protocol, supported_response ("MT") ? "MT text " : "M "); - buf_append_buffer (protocol, saved_output); - buf_output (protocol, "\n", 1); - buf_send_counted (protocol); - } - /* For now we just discard partial lines on stderr. I suspect - that CVS can't write such lines unless there is a bug. */ - - buf_free (protocol); - - /* Close the pipes explicitly in order to send an EOF to the parent, - * then wait for the parent to close the flow control pipe. This - * avoids a race condition where a child which dumped more than the - * high water mark into the pipes could complete its job and exit, - * leaving the parent process to attempt to write a stop byte to the - * closed flow control pipe, which earned the parent a SIGPIPE, which - * it normally only expects on the network pipe and that causes it to - * exit with an error message, rather than the SIGCHILD that it knows - * how to handle correctly. - */ - /* Let exit() close STDIN - it's from /dev/null anyhow. */ - fclose (stderr); - fclose (stdout); - close (protocol_pipe[1]); -#ifdef SERVER_FLOWCONTROL - { - char junk; - set_block_fd (flowcontrol_pipe[0]); - while (read (flowcontrol_pipe[0], &junk, 1) > 0); - } - /* FIXME: No point in printing an error message with error(), - * as STDERR is already closed, but perhaps this could be syslogged? - */ -#endif - - rcs_cleanup (); - Lock_Cleanup (); - /* Don't call server_cleanup - the parent will handle that. */ -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - exit (exitstatus); - } - - /* OK, sit around getting all the input from the child. */ - { - struct buffer *stdoutbuf = NULL; - struct buffer *stderrbuf = NULL; - struct buffer *protocol_inbuf = NULL; - int err_exit = 0; - /* Number of file descriptors to check in select (). */ - int num_to_check; - int count_needed = 1; -#ifdef SERVER_FLOWCONTROL - int have_flowcontrolled = 0; -#endif /* SERVER_FLOWCONTROL */ - - FD_ZERO (&command_fds_to_drain.fds); - num_to_check = stdout_pipe[0]; - FD_SET (stdout_pipe[0], &command_fds_to_drain.fds); - if (stderr_pipe[0] > num_to_check) - num_to_check = stderr_pipe[0]; - FD_SET (stderr_pipe[0], &command_fds_to_drain.fds); - if (protocol_pipe[0] > num_to_check) - num_to_check = protocol_pipe[0]; - FD_SET (protocol_pipe[0], &command_fds_to_drain.fds); - if (STDOUT_FILENO > num_to_check) - num_to_check = STDOUT_FILENO; -#ifdef SUNOS_KLUDGE - max_command_fd = num_to_check; -#endif - /* - * File descriptors are numbered from 0, so num_to_check needs to - * be one larger than the largest descriptor. - */ - ++num_to_check; - if (num_to_check > FD_SETSIZE) - { - buf_output0 (buf_to_net, - "E internal error: FD_SETSIZE not big enough.\n\ -error \n"); - goto error_exit; - } - - stdoutbuf = fd_buffer_initialize (stdout_pipe[0], 1, - input_memory_error); - - stderrbuf = fd_buffer_initialize (stderr_pipe[0], 1, - input_memory_error); - - protocol_inbuf = fd_buffer_initialize (protocol_pipe[0], 1, - input_memory_error); - - set_nonblock (buf_to_net); - set_nonblock (stdoutbuf); - set_nonblock (stderrbuf); - set_nonblock (protocol_inbuf); - - if (close (stdout_pipe[1]) < 0) - { - buf_output0 (buf_to_net, "E close failed\n"); - print_error (errno); - err_exit = 1; - goto child_finish; - } - stdout_pipe[1] = -1; - - if (close (stderr_pipe[1]) < 0) - { - buf_output0 (buf_to_net, "E close failed\n"); - print_error (errno); - err_exit = 1; - goto child_finish; - } - stderr_pipe[1] = -1; - - if (close (protocol_pipe[1]) < 0) - { - buf_output0 (buf_to_net, "E close failed\n"); - print_error (errno); - err_exit = 1; - goto child_finish; - } - protocol_pipe[1] = -1; - -#ifdef SERVER_FLOWCONTROL - if (close (flowcontrol_pipe[0]) < 0) - { - buf_output0 (buf_to_net, "E close failed\n"); - print_error (errno); - err_exit = 1; - goto child_finish; - } - flowcontrol_pipe[0] = -1; -#endif /* SERVER_FLOWCONTROL */ - - if (close (dev_null_fd) < 0) - { - buf_output0 (buf_to_net, "E close failed\n"); - print_error (errno); - dev_null_fd = -1; /* Do not try to close it again. */ - err_exit = 1; - goto child_finish; - } - dev_null_fd = -1; - - while (stdout_pipe[0] >= 0 - || stderr_pipe[0] >= 0 - || protocol_pipe[0] >= 0 - || count_needed <= 0) - { - fd_set readfds; - fd_set writefds; - int numfds; - struct timeval *timeout_ptr; - struct timeval timeout; -#ifdef SERVER_FLOWCONTROL - int bufmemsize; - - /* - * See if we are swamping the remote client and filling our VM. - * Tell child to hold off if we do. - */ - bufmemsize = buf_count_mem (buf_to_net); - if (!have_flowcontrolled && (bufmemsize > SERVER_HI_WATER)) - { - if (write(flowcontrol_pipe[1], "S", 1) == 1) - have_flowcontrolled = 1; - } - else if (have_flowcontrolled && (bufmemsize < SERVER_LO_WATER)) - { - if (write(flowcontrol_pipe[1], "G", 1) == 1) - have_flowcontrolled = 0; - } -#endif /* SERVER_FLOWCONTROL */ - - FD_ZERO (&readfds); - FD_ZERO (&writefds); - - if (count_needed <= 0) - { - /* there is data pending which was read from the protocol pipe - * so don't block if we don't find any data - */ - timeout.tv_sec = 0; - timeout.tv_usec = 0; - timeout_ptr = &timeout; - } - else - { - /* block indefinately */ - timeout_ptr = NULL; - } - - if (! buf_empty_p (buf_to_net)) - FD_SET (STDOUT_FILENO, &writefds); - - if (stdout_pipe[0] >= 0) - { - FD_SET (stdout_pipe[0], &readfds); - } - if (stderr_pipe[0] >= 0) - { - FD_SET (stderr_pipe[0], &readfds); - } - if (protocol_pipe[0] >= 0) - { - FD_SET (protocol_pipe[0], &readfds); - } - - /* This process of selecting on the three pipes means that - we might not get output in the same order in which it - was written, thus producing the well-known - "out-of-order" bug. If the child process uses - cvs_output and cvs_outerr, it will send everything on - the protocol_pipe and avoid this problem, so the - solution is to use cvs_output and cvs_outerr in the - child process. */ - do { - /* This used to select on exceptions too, but as far - as I know there was never any reason to do that and - SCO doesn't let you select on exceptions on pipes. */ - numfds = select (num_to_check, &readfds, &writefds, - (fd_set *)0, timeout_ptr); - if (numfds < 0 - && errno != EINTR) - { - buf_output0 (buf_to_net, "E select failed\n"); - print_error (errno); - err_exit = 1; - goto child_finish; - } - } while (numfds < 0); - - if (numfds == 0) - { - FD_ZERO (&readfds); - FD_ZERO (&writefds); - } - - if (FD_ISSET (STDOUT_FILENO, &writefds)) - { - /* 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))) - { - int status; - int count_read; - - 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); - err_exit = 1; - goto child_finish; - } - - /* - * We only call buf_copy_counted if we have read - * enough bytes to make it worthwhile. This saves us - * from continually recounting the amount of data we - * have. - */ - count_needed -= count_read; - } - /* this is still part of the protocol pipe procedure, but it is - * outside the above conditional so that unprocessed data can be - * left in the buffer and stderr/stdout can be read when a flush - * signal is received and control can return here without passing - * through the select code and maybe blocking - */ - while (count_needed <= 0) - { - int special = 0; - - count_needed = buf_copy_counted (buf_to_net, - protocol_inbuf, - &special); - - /* What should we do with errors? syslog() them? */ - buf_send_output (buf_to_net); - - /* If SPECIAL got set to <0, it means that the child - * wants us to flush the pipe & maybe stderr or stdout. - * - * After that we break to read stderr & stdout again before - * going back to the protocol pipe - * - * Upon breaking, count_needed = 0, so the next pass will only - * perform a non-blocking select before returning here to finish - * processing data we already read from the protocol buffer - */ - if (special == -1) - { - cvs_flushout(); - break; - } - if (special == -2) - { - /* If the client supports the 'F' command, we send it. */ - if (supported_response ("F")) - { - buf_append_char (buf_to_net, 'F'); - buf_append_char (buf_to_net, '\n'); - } - cvs_flusherr (); - break; - } - } - - 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); - err_exit = 1; - goto child_finish; - } - - /* 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); - err_exit = 1; - goto child_finish; - } - - /* What should we do with errors? syslog() them? */ - buf_send_output (buf_to_net); - } - } - - /* - * OK, we've gotten EOF on all the pipes. If there is - * anything left on stdoutbuf or stderrbuf (this could only - * happen if there was no trailing newline), send it over. - */ - if (! buf_empty_p (stdoutbuf)) - { - buf_append_char (stdoutbuf, '\n'); - buf_copy_lines (buf_to_net, stdoutbuf, 'M'); - } - if (! buf_empty_p (stderrbuf)) - { - buf_append_char (stderrbuf, '\n'); - buf_copy_lines (buf_to_net, stderrbuf, 'E'); - } - if (! buf_empty_p (protocol_inbuf)) - 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) - { - int status; - pid_t waited_pid; - waited_pid = waitpid (command_pid, &status, 0); - if (waited_pid < 0) - { - /* - * Intentionally ignoring EINTR. Other errors - * "can't happen". - */ - continue; - } - - if (WIFEXITED (status)) - errs += WEXITSTATUS (status); - else - { - int sig = WTERMSIG (status); - char buf[50]; - /* - * This is really evil, because signals might be numbered - * differently on the two systems. We should be using - * signal names (either of the "Terminated" or the "SIGTERM" - * variety). But cvs doesn't currently use libiberty...we - * could roll our own.... FIXME. - */ - buf_output0 (buf_to_net, "E Terminated with fatal signal "); - sprintf (buf, "%d\n", sig); - buf_output0 (buf_to_net, buf); - - /* Test for a core dump. */ - if (WCOREDUMP (status)) - { - buf_output0 (buf_to_net, "E Core dumped; preserving "); - buf_output0 (buf_to_net, orig_server_temp_dir); - buf_output0 (buf_to_net, " on server.\n\ -E CVS locks may need cleaning up.\n"); - dont_delete_temp = 1; - } - ++errs; - } - if (waited_pid == command_pid) - command_pid = -1; - } - - child_finish: - /* - * OK, we've waited for the child. By now all CVS locks are free - * and it's OK to block on the network. - */ - set_block (buf_to_net); - buf_flush (buf_to_net, 1); - if (protocol_inbuf) - { - buf_shutdown (protocol_inbuf); - buf_free (protocol_inbuf); - protocol_inbuf = NULL; - } - if (stderrbuf) - { - buf_shutdown (stderrbuf); - buf_free (stderrbuf); - stderrbuf = NULL; - } - if (stdoutbuf) - { - buf_shutdown (stdoutbuf); - buf_free (stdoutbuf); - stdoutbuf = NULL; - } - if (err_exit) - goto error_exit; - } - - if (errs) - /* We will have printed an error message already. */ - buf_output0 (buf_to_net, "error \n"); - else - buf_output0 (buf_to_net, "ok\n"); - goto free_args_and_return; - - error_exit: - if (command_pid > 0) - kill (command_pid, SIGTERM); - - while (command_pid > 0) - { - pid_t waited_pid; - waited_pid = waitpid (command_pid, (int *) 0, 0); - if (waited_pid < 0 && errno == EINTR) - continue; - if (waited_pid == command_pid) - command_pid = -1; - } - - if (dev_null_fd >= 0) - close (dev_null_fd); - close (protocol_pipe[0]); - close (protocol_pipe[1]); - close (stderr_pipe[0]); - 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. */ - { - /* argument_vector[0] is a dummy argument, we don't mess with it. */ - char **cp; - for (cp = argument_vector + 1; - cp < argument_vector + argument_count; - ++cp) - free (*cp); - - argument_count = 1; - } - - /* Flush out any data not yet sent. */ - set_block (buf_to_net); - buf_flush (buf_to_net, 1); - - return; -} - -#ifdef SERVER_FLOWCONTROL -/* - * Called by the child at convenient points in the server's execution for - * the server child to block.. ie: when it has no locks active. - */ -void -server_pause_check() -{ - int paused = 0; - char buf[1]; - - while (read (flowcontrol_pipe[0], buf, 1) == 1) - { - if (*buf == 'S') /* Stop */ - paused = 1; - else if (*buf == 'G') /* Go */ - paused = 0; - else - return; /* ??? */ - } - while (paused) { - int numfds, numtocheck; - fd_set fds; - - FD_ZERO (&fds); - FD_SET (flowcontrol_pipe[0], &fds); - numtocheck = flowcontrol_pipe[0] + 1; - - do { - numfds = select (numtocheck, &fds, (fd_set *)0, - (fd_set *)0, (struct timeval *)NULL); - if (numfds < 0 - && errno != EINTR) - { - buf_output0 (buf_to_net, "E select failed\n"); - print_error (errno); - return; - } - } while (numfds < 0); - - if (FD_ISSET (flowcontrol_pipe[0], &fds)) - { - int got; - - while ((got = read (flowcontrol_pipe[0], buf, 1)) == 1) - { - if (*buf == 'S') /* Stop */ - paused = 1; - else if (*buf == 'G') /* Go */ - paused = 0; - else - return; /* ??? */ - } - - /* This assumes that we are using BSD or POSIX nonblocking - I/O. System V nonblocking I/O returns zero if there is - nothing to read. */ - if (got == 0) - error (1, 0, "flow control EOF"); - if (got < 0 && ! blocking_error (errno)) - { - error (1, errno, "flow control read failed"); - } - } - } -} -#endif /* SERVER_FLOWCONTROL */ - -/* This variable commented in server.h. */ -char *server_dir = NULL; - - - -static void output_dir PROTO((const char *, const char *)); - -static void -output_dir (update_dir, repository) - const char *update_dir; - const char *repository; -{ - if (server_dir != NULL) - { - buf_output0 (protocol, server_dir); - buf_output0 (protocol, "/"); - } - if (update_dir[0] == '\0') - buf_output0 (protocol, "."); - else - buf_output0 (protocol, update_dir); - buf_output0 (protocol, "/\n"); - buf_output0 (protocol, repository); - buf_output0 (protocol, "/"); -} - - - -/* - * Entries line that we are squirreling away to send to the client when - * we are ready. - */ -static char *entries_line; - -/* - * File which has been Scratch_File'd, we are squirreling away that fact - * to inform the client when we are ready. - */ -static char *scratched_file; - -/* - * The scratched_file will need to be removed as well as having its entry - * removed. - */ -static int kill_scratched_file; - - - -void -server_register (name, version, timestamp, options, tag, date, conflict) - const char *name; - const char *version; - const char *timestamp; - const char *options; - const char *tag; - const char *date; - const char *conflict; -{ - int len; - - if (options == NULL) - options = ""; - - if (trace) - { - (void) fprintf (stderr, - "%s-> server_register(%s, %s, %s, %s, %s, %s, %s)\n", - CLIENT_SERVER_STR, - name, version, timestamp ? timestamp : "", options, - tag ? tag : "", date ? date : "", - conflict ? conflict : ""); - } - - if (entries_line != NULL) - { - /* - * If CVS decides to Register it more than once (which happens - * on "cvs update foo/foo.c" where foo and foo.c are already - * checked out), use the last of the entries lines Register'd. - */ - free (entries_line); - } - - /* - * I have reports of Scratch_Entry and Register both happening, in - * two different cases. Using the last one which happens is almost - * surely correct; I haven't tracked down why they both happen (or - * even verified that they are for the same file). - */ - if (scratched_file != NULL) - { - free (scratched_file); - scratched_file = NULL; - } - - len = (strlen (name) + strlen (version) + strlen (options) + 80); - if (tag) - len += strlen (tag); - if (date) - len += strlen (date); - - entries_line = xmalloc (len); - sprintf (entries_line, "/%s/%s/", name, version); - if (conflict != NULL) - { - strcat (entries_line, "+="); - } - strcat (entries_line, "/"); - strcat (entries_line, options); - strcat (entries_line, "/"); - if (tag != NULL) - { - strcat (entries_line, "T"); - strcat (entries_line, tag); - } - else if (date != NULL) - { - strcat (entries_line, "D"); - strcat (entries_line, date); - } -} - - - -void -server_scratch (fname) - const char *fname; -{ - /* - * I have reports of Scratch_Entry and Register both happening, in - * two different cases. Using the last one which happens is almost - * surely correct; I haven't tracked down why they both happen (or - * even verified that they are for the same file). - * - * Don't know if this is what whoever wrote the above comment was - * talking about, but this can happen in the case where a join - * removes a file - the call to Register puts the '-vers' into the - * Entries file after the file is removed - */ - if (entries_line != NULL) - { - free (entries_line); - entries_line = NULL; - } - - if (scratched_file != NULL) - { - buf_output0 (protocol, - "E CVS server internal error: duplicate Scratch_Entry\n"); - buf_send_counted (protocol); - return; - } - scratched_file = xstrdup (fname); - kill_scratched_file = 1; -} - -void -server_scratch_entry_only () -{ - kill_scratched_file = 0; -} - -/* Print a new entries line, from a previous server_register. */ -static void -new_entries_line () -{ - if (entries_line) - { - buf_output0 (protocol, entries_line); - buf_output (protocol, "\n", 1); - } - else - /* Return the error message as the Entries line. */ - buf_output0 (protocol, - "CVS server internal error: Register missing\n"); - free (entries_line); - entries_line = NULL; -} - - -static void -serve_ci (arg) - char *arg; -{ - do_cvs_command ("commit", commit); -} - -static void -checked_in_response (file, update_dir, repository) - char *file; - char *update_dir; - char *repository; -{ - if (supported_response ("Mode")) - { - struct stat sb; - char *mode_string; - - if ( CVS_STAT (file, &sb) < 0) - { - /* Not clear to me why the file would fail to exist, but it - was happening somewhere in the testsuite. */ - if (!existence_error (errno)) - error (0, errno, "cannot stat %s", file); - } - else - { - buf_output0 (protocol, "Mode "); - mode_string = mode_to_string (sb.st_mode); - buf_output0 (protocol, mode_string); - buf_output0 (protocol, "\n"); - free (mode_string); - } - } - - buf_output0 (protocol, "Checked-in "); - output_dir (update_dir, repository); - buf_output0 (protocol, file); - buf_output (protocol, "\n", 1); - new_entries_line (); -} - -void -server_checked_in (file, update_dir, repository) - const char *file; - const char *update_dir; - const char *repository; -{ - assert (file); - assert (update_dir); - assert (repository); - - if (noexec) - return; - if (scratched_file != NULL && entries_line == NULL) - { - /* - * This happens if we are now doing a "cvs remove" after a previous - * "cvs add" (without a "cvs ci" in between). - */ - buf_output0 (protocol, "Remove-entry "); - output_dir (update_dir, repository); - buf_output0 (protocol, file); - buf_output (protocol, "\n", 1); - free (scratched_file); - scratched_file = NULL; - } - else - { - checked_in_response (file, update_dir, repository); - } - buf_send_counted (protocol); -} - -void -server_update_entries (file, update_dir, repository, updated) - const char *file; - const char *update_dir; - const char *repository; - enum server_updated_arg4 updated; -{ - if (noexec) - return; - if (updated == SERVER_UPDATED) - checked_in_response (file, update_dir, repository); - else - { - if (!supported_response ("New-entry")) - return; - buf_output0 (protocol, "New-entry "); - output_dir (update_dir, repository); - buf_output0 (protocol, file); - buf_output (protocol, "\n", 1); - new_entries_line (); - } - - buf_send_counted (protocol); -} - -static void -serve_update (arg) - char *arg; -{ - do_cvs_command ("update", update); -} - -static void -serve_diff (arg) - char *arg; -{ - do_cvs_command ("diff", diff); -} - -static void -serve_log (arg) - char *arg; -{ - do_cvs_command ("log", cvslog); -} - -static void -serve_rlog (arg) - char *arg; -{ - do_cvs_command ("rlog", cvslog); -} - -static void -serve_add (arg) - char *arg; -{ - do_cvs_command ("add", add); -} - -static void -serve_remove (arg) - char *arg; -{ - do_cvs_command ("remove", cvsremove); -} - -static void -serve_status (arg) - char *arg; -{ - do_cvs_command ("status", cvsstatus); -} - -static void -serve_rdiff (arg) - char *arg; -{ - do_cvs_command ("rdiff", patch); -} - -static void -serve_tag (arg) - char *arg; -{ - do_cvs_command ("tag", cvstag); -} - -static void -serve_rtag (arg) - char *arg; -{ - do_cvs_command ("rtag", cvstag); -} - -static void -serve_import (arg) - char *arg; -{ - do_cvs_command ("import", import); -} - -static void -serve_admin (arg) - char *arg; -{ - do_cvs_command ("admin", admin); -} - -static void -serve_history (arg) - char *arg; -{ - do_cvs_command ("history", history); -} - -static void -serve_release (arg) - char *arg; -{ - do_cvs_command ("release", release); -} - -static void serve_watch_on PROTO ((char *)); - -static void -serve_watch_on (arg) - char *arg; -{ - do_cvs_command ("watch", watch_on); -} - -static void serve_watch_off PROTO ((char *)); - -static void -serve_watch_off (arg) - char *arg; -{ - do_cvs_command ("watch", watch_off); -} - -static void serve_watch_add PROTO ((char *)); - -static void -serve_watch_add (arg) - char *arg; -{ - do_cvs_command ("watch", watch_add); -} - -static void serve_watch_remove PROTO ((char *)); - -static void -serve_watch_remove (arg) - char *arg; -{ - do_cvs_command ("watch", watch_remove); -} - -static void serve_watchers PROTO ((char *)); - -static void -serve_watchers (arg) - char *arg; -{ - do_cvs_command ("watchers", watchers); -} - -static void serve_editors PROTO ((char *)); - -static void -serve_editors (arg) - char *arg; -{ - do_cvs_command ("editors", editors); -} - -static void serve_noop PROTO ((char *)); - -static void -serve_noop (arg) - char *arg; -{ - - 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_version PROTO ((char *)); - -static void -serve_version (arg) - char *arg; -{ - do_cvs_command ("version", version); -} - -static void serve_init PROTO ((char *)); - -static void -serve_init (arg) - char *arg; -{ - if (alloc_pending (80 + strlen (arg))) - sprintf (pending_error_text, "E init may not be run remotely"); - - if (print_pending_error ()) - return; -} - -static void serve_annotate PROTO ((char *)); - -static void -serve_annotate (arg) - char *arg; -{ - do_cvs_command ("annotate", annotate); -} - -static void serve_rannotate PROTO ((char *)); - -static void -serve_rannotate (arg) - char *arg; -{ - do_cvs_command ("rannotate", annotate); -} - -static void -serve_co (arg) - char *arg; -{ - char *tempdir; - int status; - - if (print_pending_error ()) - return; - - if (!isdir (CVSADM)) - { - /* - * The client has not sent a "Repository" line. Check out - * into a pristine directory. - */ - tempdir = xmalloc (strlen (server_temp_dir) + 80); - if (tempdir == NULL) - { - buf_output0 (buf_to_net, "E Out of memory\n"); - return; - } - strcpy (tempdir, server_temp_dir); - strcat (tempdir, "/checkout-dir"); - status = mkdir_p (tempdir); - if (status != 0 && status != EEXIST) - { - buf_output0 (buf_to_net, "E Cannot create "); - buf_output0 (buf_to_net, tempdir); - buf_append_char (buf_to_net, '\n'); - print_error (errno); - free (tempdir); - return; - } - - if ( CVS_CHDIR (tempdir) < 0) - { - buf_output0 (buf_to_net, "E Cannot change to directory "); - buf_output0 (buf_to_net, tempdir); - buf_append_char (buf_to_net, '\n'); - print_error (errno); - free (tempdir); - return; - } - free (tempdir); - } - - /* Compensate for server_export()'s setting of cvs_cmd_name. - * - * [It probably doesn't matter if do_cvs_command() gets "export" - * or "checkout", but we ought to be accurate where possible.] - */ - do_cvs_command ((strcmp (cvs_cmd_name, "export") == 0) ? - "export" : "checkout", - checkout); -} - -static void -serve_export (arg) - char *arg; -{ - /* Tell checkout() to behave like export not checkout. */ - cvs_cmd_name = "export"; - serve_co (arg); -} - - - -void -server_copy_file (file, update_dir, repository, newfile) - const char *file; - const char *update_dir; - const char *repository; - const char *newfile; -{ - /* At least for now, our practice is to have the server enforce - noexec for the repository and the client enforce it for the - working directory. This might want more thought, and/or - documentation in cvsclient.texi (other responses do it - differently). */ - - if (!supported_response ("Copy-file")) - return; - buf_output0 (protocol, "Copy-file "); - output_dir (update_dir, repository); - buf_output0 (protocol, file); - buf_output0 (protocol, "\n"); - buf_output0 (protocol, newfile); - buf_output0 (protocol, "\n"); -} - -/* See server.h for description. */ - -void -server_modtime (finfo, vers_ts) - struct file_info *finfo; - Vers_TS *vers_ts; -{ - char date[MAXDATELEN]; - char outdate[MAXDATELEN]; - - assert (vers_ts->vn_rcs != NULL); - - if (!supported_response ("Mod-time")) - return; - - if (RCS_getrevtime (finfo->rcs, vers_ts->vn_rcs, date, 0) == (time_t) -1) - /* FIXME? should we be printing some kind of warning? For one - thing I'm not 100% sure whether this happens in non-error - circumstances. */ - return; - date_to_internet (outdate, date); - buf_output0 (protocol, "Mod-time "); - buf_output0 (protocol, outdate); - buf_output0 (protocol, "\n"); -} - -/* See server.h for description. */ - -#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) -/* Need to prototype because mode_t might be smaller than int. */ -void -server_updated ( - struct file_info *finfo, - Vers_TS *vers, - enum server_updated_arg4 updated, - mode_t mode, - unsigned char *checksum, - struct buffer *filebuf) -#else -void -server_updated (finfo, vers, updated, mode, checksum, filebuf) - struct file_info *finfo; - Vers_TS *vers; - enum server_updated_arg4 updated; - mode_t mode; - unsigned char *checksum; - struct buffer *filebuf; -#endif -{ - if (noexec) - { - /* Hmm, maybe if we did the same thing for entries_file, we - could get rid of the kludges in server_register and - server_scratch which refrain from warning if both - Scratch_Entry and Register get called. Maybe. */ - if (scratched_file) - { - free (scratched_file); - scratched_file = NULL; - } - buf_send_counted (protocol); - return; - } - - if (entries_line != NULL && scratched_file == NULL) - { - FILE *f; - struct buffer_data *list, *last; - unsigned long size; - char size_text[80]; - - /* The contents of the file will be in one of filebuf, - list/last, or here. */ - unsigned char *file; - size_t file_allocated; - size_t file_used; - - if (filebuf != NULL) - { - size = buf_length (filebuf); - if (mode == (mode_t) -1) - error (1, 0, "\ -CVS server internal error: no mode in server_updated"); - } - else - { - struct stat sb; - - if ( CVS_STAT (finfo->file, &sb) < 0) - { - if (existence_error (errno)) - { - /* If we have a sticky tag for a branch on which - the file is dead, and cvs update the directory, - it gets a T_CHECKOUT but no file. So in this - case just forget the whole thing. */ - free (entries_line); - entries_line = NULL; - goto done; - } - error (1, errno, "reading %s", finfo->fullname); - } - size = sb.st_size; - if (mode == (mode_t) -1) - { - /* FIXME: When we check out files the umask of the - server (set in .bashrc if rsh is in use) affects - what mode we send, and it shouldn't. */ - mode = sb.st_mode; - } - } - - if (checksum != NULL) - { - static int checksum_supported = -1; - - if (checksum_supported == -1) - { - checksum_supported = supported_response ("Checksum"); - } - - if (checksum_supported) - { - int i; - char buf[3]; - - buf_output0 (protocol, "Checksum "); - for (i = 0; i < 16; i++) - { - sprintf (buf, "%02x", (unsigned int) checksum[i]); - buf_output0 (protocol, buf); - } - buf_append_char (protocol, '\n'); - } - } - - if (updated == SERVER_UPDATED) - { - Node *node; - - if (!(supported_response ("Created") - && supported_response ("Update-existing"))) - buf_output0 (protocol, "Updated "); - else - { - assert (vers != NULL); - if (vers->ts_user == NULL) - buf_output0 (protocol, "Created "); - else - buf_output0 (protocol, "Update-existing "); - } - - /* Now munge the entries to say that the file is unmodified, - in case we end up processing it again (e.g. modules3-6 - in the testsuite). */ - node = findnode_fn (finfo->entries, finfo->file); - assert (node != NULL); - if (node != NULL) - { - Entnode *entnode = node->data; - free (entnode->timestamp); - entnode->timestamp = xstrdup ("="); - } - } - else if (updated == SERVER_MERGED) - buf_output0 (protocol, "Merged "); - else if (updated == SERVER_PATCHED) - buf_output0 (protocol, "Patched "); - else if (updated == SERVER_RCS_DIFF) - buf_output0 (protocol, "Rcs-diff "); - else - abort (); - output_dir (finfo->update_dir, finfo->repository); - buf_output0 (protocol, finfo->file); - buf_output (protocol, "\n", 1); - - new_entries_line (); - - { - char *mode_string; - - mode_string = mode_to_string (mode); - buf_output0 (protocol, mode_string); - buf_output0 (protocol, "\n"); - free (mode_string); - } - - list = last = NULL; - - file = NULL; - file_allocated = 0; - file_used = 0; - - if (size > 0) - { - /* Throughout this section we use binary mode to read the - file we are sending. The client handles any line ending - translation if necessary. */ - - if (file_gzip_level - /* - * For really tiny files, the gzip process startup - * time will outweigh the compression savings. This - * might be computable somehow; using 100 here is just - * a first approximation. - */ - && size > 100) - { - /* Basing this routine on read_and_gzip is not a - high-performance approach. But it seems easier - to code than the alternative (and less - vulnerable to subtle bugs). Given that this feature - is mainly for compatibility, that is the better - tradeoff. */ - - int fd; - - /* Callers must avoid passing us a buffer if - file_gzip_level is set. We could handle this case, - but it's not worth it since this case never arises - with a current client and server. */ - if (filebuf != NULL) - error (1, 0, "\ -CVS server internal error: unhandled case in server_updated"); - - fd = CVS_OPEN (finfo->file, O_RDONLY | OPEN_BINARY, 0); - if (fd < 0) - error (1, errno, "reading %s", finfo->fullname); - if (read_and_gzip (fd, finfo->fullname, &file, - &file_allocated, &file_used, - file_gzip_level)) - error (1, 0, "aborting due to compression error"); - size = file_used; - if (close (fd) < 0) - error (1, errno, "reading %s", finfo->fullname); - /* Prepending length with "z" is flag for using gzip here. */ - buf_output0 (protocol, "z"); - } - else if (filebuf == NULL) - { - long status; - - f = CVS_FOPEN (finfo->file, "rb"); - if (f == NULL) - error (1, errno, "reading %s", finfo->fullname); - status = buf_read_file (f, size, &list, &last); - if (status == -2) - (*protocol->memory_error) (protocol); - else if (status != 0) - error (1, ferror (f) ? errno : 0, "reading %s", - finfo->fullname); - if (fclose (f) == EOF) - error (1, errno, "reading %s", finfo->fullname); - } - } - - sprintf (size_text, "%lu\n", size); - buf_output0 (protocol, size_text); - - if (file != NULL) - { - buf_output (protocol, (char *) file, file_used); - free (file); - file = NULL; - } - else if (filebuf == NULL) - buf_append_data (protocol, list, last); - else - { - buf_append_buffer (protocol, filebuf); - } - /* Note we only send a newline here if the file ended with one. */ - - /* - * Avoid using up too much disk space for temporary files. - * A file which does not exist indicates that the file is up-to-date, - * which is now the case. If this is SERVER_MERGED, the file is - * not up-to-date, and we indicate that by leaving the file there. - * I'm thinking of cases like "cvs update foo/foo.c foo". - */ - if ((updated == SERVER_UPDATED - || updated == SERVER_PATCHED - || updated == SERVER_RCS_DIFF) - && filebuf == NULL - /* But if we are joining, we'll need the file when we call - join_file. */ - && !joining ()) - { - if (CVS_UNLINK (finfo->file) < 0) - error (0, errno, "cannot remove temp file for %s", - finfo->fullname); - } - } - else if (scratched_file != NULL && entries_line == NULL) - { - if (strcmp (scratched_file, finfo->file) != 0) - error (1, 0, - "CVS server internal error: `%s' vs. `%s' scratched", - scratched_file, - finfo->file); - free (scratched_file); - scratched_file = NULL; - - if (kill_scratched_file) - buf_output0 (protocol, "Removed "); - else - buf_output0 (protocol, "Remove-entry "); - output_dir (finfo->update_dir, finfo->repository); - buf_output0 (protocol, finfo->file); - buf_output (protocol, "\n", 1); - /* keep the vers structure up to date in case we do a join - * - if there isn't a file, it can't very well have a version number, can it? - * - * we do it here on the assumption that since we just told the client - * to remove the file/entry, it will, and we want to remember that. - * If it fails, that's the client's problem, not ours - */ - if (vers && vers->vn_user != NULL) - { - free (vers->vn_user); - vers->vn_user = NULL; - } - if (vers && vers->ts_user != NULL) - { - free (vers->ts_user); - vers->ts_user = NULL; - } - } - else if (scratched_file == NULL && entries_line == NULL) - { - /* - * This can happen with death support if we were processing - * a dead file in a checkout. - */ - } - else - error (1, 0, - "CVS server internal error: Register *and* Scratch_Entry.\n"); - buf_send_counted (protocol); - done:; -} - -/* Return whether we should send patches in RCS format. */ - -int -server_use_rcs_diff () -{ - return supported_response ("Rcs-diff"); -} - - - -void -server_set_entstat (update_dir, repository) - const char *update_dir; - const char *repository; -{ - static int set_static_supported = -1; - if (set_static_supported == -1) - set_static_supported = supported_response ("Set-static-directory"); - if (!set_static_supported) return; - - buf_output0 (protocol, "Set-static-directory "); - output_dir (update_dir, repository); - buf_output0 (protocol, "\n"); - buf_send_counted (protocol); -} - - - -void -server_clear_entstat (update_dir, repository) - const char *update_dir; - const char *repository; -{ - static int clear_static_supported = -1; - if (clear_static_supported == -1) - clear_static_supported = supported_response ("Clear-static-directory"); - if (!clear_static_supported) return; - - if (noexec) - return; - - buf_output0 (protocol, "Clear-static-directory "); - output_dir (update_dir, repository); - buf_output0 (protocol, "\n"); - buf_send_counted (protocol); -} - - - -void -server_set_sticky (update_dir, repository, tag, date, nonbranch) - const char *update_dir; - const char *repository; - const char *tag; - const char *date; - int nonbranch; -{ - static int set_sticky_supported = -1; - - assert (update_dir != NULL); - - if (set_sticky_supported == -1) - set_sticky_supported = supported_response ("Set-sticky"); - if (!set_sticky_supported) return; - - if (noexec) - return; - - if (tag == NULL && date == NULL) - { - buf_output0 (protocol, "Clear-sticky "); - output_dir (update_dir, repository); - buf_output0 (protocol, "\n"); - } - else - { - buf_output0 (protocol, "Set-sticky "); - output_dir (update_dir, repository); - buf_output0 (protocol, "\n"); - if (tag != NULL) - { - if (nonbranch) - buf_output0 (protocol, "N"); - else - buf_output0 (protocol, "T"); - buf_output0 (protocol, tag); - } - else - { - buf_output0 (protocol, "D"); - buf_output0 (protocol, date); - } - buf_output0 (protocol, "\n"); - } - buf_send_counted (protocol); -} - -struct template_proc_data -{ - const char *update_dir; - const char *repository; -}; - -/* Here as a static until we get around to fixing Parse_Info to pass along - a void * for it. */ -static struct template_proc_data *tpd; - -static int -template_proc PROTO((const char *repository, const char *template)); - -static int -template_proc (repository, template) - const char *repository; - const char *template; -{ - FILE *fp; - char buf[1024]; - size_t n; - struct stat sb; - struct template_proc_data *data = tpd; - - if (!supported_response ("Template")) - /* Might want to warn the user that the rcsinfo feature won't work. */ - return 0; - buf_output0 (protocol, "Template "); - output_dir (data->update_dir, data->repository); - buf_output0 (protocol, "\n"); - - fp = CVS_FOPEN (template, "rb"); - if (fp == NULL) - { - error (0, errno, "Couldn't open rcsinfo template file %s", template); - return 1; - } - if (fstat (fileno (fp), &sb) < 0) - { - error (0, errno, "cannot stat rcsinfo template file %s", template); - return 1; - } - sprintf (buf, "%ld\n", (long) sb.st_size); - buf_output0 (protocol, buf); - while (!feof (fp)) - { - n = fread (buf, 1, sizeof buf, fp); - buf_output (protocol, buf, n); - if (ferror (fp)) - { - error (0, errno, "cannot read rcsinfo template file %s", template); - (void) fclose (fp); - return 1; - } - } - buf_send_counted (protocol); - if (fclose (fp) < 0) - error (0, errno, "cannot close rcsinfo template file %s", template); - return 0; -} - - - -void -server_template (update_dir, repository) - const char *update_dir; - const char *repository; -{ - struct template_proc_data data; - data.update_dir = update_dir; - data.repository = repository; - tpd = &data; - (void) Parse_Info (CVSROOTADM_RCSINFO, repository, template_proc, 1); -} - - - -static void -serve_gzip_contents (arg) - char *arg; -{ - int level; - level = atoi (arg); - if (level == 0) - level = 6; - file_gzip_level = level; -} - -static void -serve_gzip_stream (arg) - char *arg; -{ - int level; - level = atoi (arg); - if (level == 0) - level = 6; - - /* All further communication with the client will be compressed. */ - - buf_to_net = compress_buffer_initialize (buf_to_net, 0, level, - buf_to_net->memory_error); - buf_from_net = compress_buffer_initialize (buf_from_net, 1, level, - buf_from_net->memory_error); -} - -/* Tell the client about RCS options set in CVSROOT/cvswrappers. */ -static void -serve_wrapper_sendme_rcs_options (arg) - char *arg; -{ - /* Actually, this is kind of sdrawkcab-ssa: the client wants - * verbatim lines from a cvswrappers file, but the server has - * already parsed the cvswrappers file into the wrap_list struct. - * Therefore, the server loops over wrap_list, unparsing each - * entry before sending it. - */ - char *wrapper_line = NULL; - - wrap_setup (); - - for (wrap_unparse_rcs_options (&wrapper_line, 1); - wrapper_line; - wrap_unparse_rcs_options (&wrapper_line, 0)) - { - buf_output0 (buf_to_net, "Wrapper-rcsOption "); - buf_output0 (buf_to_net, wrapper_line); - buf_output0 (buf_to_net, "\012");; - free (wrapper_line); - } - - buf_output0 (buf_to_net, "ok\012"); - - /* The client is waiting for us, so we better send the data now. */ - buf_flush (buf_to_net, 1); -} - - -static void -serve_ignore (arg) - char *arg; -{ - /* - * Just ignore this command. This is used to support the - * update-patches command, which is not a real command, but a signal - * to the client that update will accept the -u argument. - */ -} - -static int -expand_proc (argc, argv, where, mwhere, mfile, shorten, - local_specified, omodule, msg) - int argc; - char **argv; - char *where; - char *mwhere; - char *mfile; - int shorten; - int local_specified; - char *omodule; - char *msg; -{ - int i; - char *dir = argv[0]; - - /* If mwhere has been specified, the thing we're expanding is a - module -- just return its name so the client will ask for the - right thing later. If it is an alias or a real directory, - mwhere will not be set, so send out the appropriate - expansion. */ - - if (mwhere != NULL) - { - buf_output0 (buf_to_net, "Module-expansion "); - if (server_dir != NULL) - { - buf_output0 (buf_to_net, server_dir); - buf_output0 (buf_to_net, "/"); - } - buf_output0 (buf_to_net, mwhere); - if (mfile != NULL) - { - buf_append_char (buf_to_net, '/'); - buf_output0 (buf_to_net, mfile); - } - buf_append_char (buf_to_net, '\n'); - } - else - { - /* We may not need to do this anymore -- check the definition - of aliases before removing */ - if (argc == 1) - { - buf_output0 (buf_to_net, "Module-expansion "); - if (server_dir != NULL) - { - buf_output0 (buf_to_net, server_dir); - buf_output0 (buf_to_net, "/"); - } - buf_output0 (buf_to_net, dir); - buf_append_char (buf_to_net, '\n'); - } - else - { - for (i = 1; i < argc; ++i) - { - buf_output0 (buf_to_net, "Module-expansion "); - if (server_dir != NULL) - { - buf_output0 (buf_to_net, server_dir); - buf_output0 (buf_to_net, "/"); - } - buf_output0 (buf_to_net, dir); - buf_append_char (buf_to_net, '/'); - buf_output0 (buf_to_net, argv[i]); - buf_append_char (buf_to_net, '\n'); - } - } - } - return 0; -} - -static void -serve_expand_modules (arg) - char *arg; -{ - int i; - int err; - DBM *db; - err = 0; - - db = open_module (); - for (i = 1; i < argument_count; i++) - err += do_module (db, argument_vector[i], - CHECKOUT, "Updating", expand_proc, - NULL, 0, 0, 0, 0, - (char *) NULL); - close_module (db); - { - /* argument_vector[0] is a dummy argument, we don't mess with it. */ - char **cp; - for (cp = argument_vector + 1; - cp < argument_vector + argument_count; - ++cp) - free (*cp); - - argument_count = 1; - } - if (err) - /* We will have printed an error message already. */ - buf_output0 (buf_to_net, "error \n"); - else - buf_output0 (buf_to_net, "ok\n"); - - /* The client is waiting for the module expansions, so we must - send the output now. */ - buf_flush (buf_to_net, 1); -} - - - -static void serve_valid_requests PROTO((char *arg)); - -#endif /* SERVER_SUPPORT */ -#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) - -/* - * Parts of this table are shared with the client code, - * but the client doesn't need to know about the handler - * functions. - */ - -struct request requests[] = -{ -#ifdef SERVER_SUPPORT -#define REQ_LINE(n, f, s) {n, f, s} -#else -#define REQ_LINE(n, f, s) {n, s} -#endif - - REQ_LINE("Root", serve_root, RQ_ESSENTIAL | RQ_ROOTLESS), - REQ_LINE("Valid-responses", serve_valid_responses, - RQ_ESSENTIAL | RQ_ROOTLESS), - REQ_LINE("valid-requests", serve_valid_requests, - RQ_ESSENTIAL | RQ_ROOTLESS), - REQ_LINE("Repository", serve_repository, 0), - REQ_LINE("Directory", serve_directory, RQ_ESSENTIAL), - REQ_LINE("Max-dotdot", serve_max_dotdot, 0), - REQ_LINE("Static-directory", serve_static_directory, 0), - REQ_LINE("Sticky", serve_sticky, 0), - REQ_LINE("Entry", serve_entry, RQ_ESSENTIAL), - REQ_LINE("Kopt", serve_kopt, 0), - REQ_LINE("Checkin-time", serve_checkin_time, 0), - REQ_LINE("Modified", serve_modified, RQ_ESSENTIAL), - REQ_LINE("Is-modified", serve_is_modified, 0), - REQ_LINE("Empty-conflicts", serve_noop, 0), - - /* The client must send this request to interoperate with CVS 1.5 - through 1.9 servers. The server must support it (although it can - be and is a noop) to interoperate with CVS 1.5 to 1.9 clients. */ - REQ_LINE("UseUnchanged", serve_enable_unchanged, RQ_ENABLEME | RQ_ROOTLESS), - - REQ_LINE("Unchanged", serve_unchanged, RQ_ESSENTIAL), - REQ_LINE("Notify", serve_notify, 0), - REQ_LINE("Questionable", serve_questionable, 0), - REQ_LINE("Argument", serve_argument, RQ_ESSENTIAL), - REQ_LINE("Argumentx", serve_argumentx, RQ_ESSENTIAL), - 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, - 0), - REQ_LINE("Set", serve_set, RQ_ROOTLESS), -#ifdef ENCRYPTION -# ifdef HAVE_KERBEROS - REQ_LINE("Kerberos-encrypt", serve_kerberos_encrypt, 0), -# endif -# ifdef HAVE_GSSAPI - REQ_LINE("Gssapi-encrypt", serve_gssapi_encrypt, 0), -# endif -#endif -#ifdef HAVE_GSSAPI - REQ_LINE("Gssapi-authenticate", serve_gssapi_authenticate, 0), -#endif - REQ_LINE("expand-modules", serve_expand_modules, 0), - REQ_LINE("ci", serve_ci, RQ_ESSENTIAL), - REQ_LINE("co", serve_co, RQ_ESSENTIAL), - REQ_LINE("update", serve_update, RQ_ESSENTIAL), - REQ_LINE("diff", serve_diff, 0), - REQ_LINE("log", serve_log, 0), - REQ_LINE("rlog", serve_rlog, 0), - REQ_LINE("add", serve_add, 0), - REQ_LINE("remove", serve_remove, 0), - REQ_LINE("update-patches", serve_ignore, 0), - REQ_LINE("gzip-file-contents", serve_gzip_contents, 0), - REQ_LINE("status", serve_status, 0), - REQ_LINE("rdiff", serve_rdiff, 0), - REQ_LINE("tag", serve_tag, 0), - REQ_LINE("rtag", serve_rtag, 0), - REQ_LINE("import", serve_import, 0), - REQ_LINE("admin", serve_admin, 0), - REQ_LINE("export", serve_export, 0), - REQ_LINE("history", serve_history, 0), - REQ_LINE("release", serve_release, 0), - REQ_LINE("watch-on", serve_watch_on, 0), - REQ_LINE("watch-off", serve_watch_off, 0), - REQ_LINE("watch-add", serve_watch_add, 0), - REQ_LINE("watch-remove", serve_watch_remove, 0), - REQ_LINE("watchers", serve_watchers, 0), - REQ_LINE("editors", serve_editors, 0), - REQ_LINE("init", serve_init, RQ_ROOTLESS), - REQ_LINE("annotate", serve_annotate, 0), - REQ_LINE("rannotate", serve_rannotate, 0), - REQ_LINE("noop", serve_noop, RQ_ROOTLESS), - REQ_LINE("version", serve_version, RQ_ROOTLESS), - REQ_LINE(NULL, NULL, 0) - -#undef REQ_LINE -}; - -#endif /* SERVER_SUPPORT or CLIENT_SUPPORT */ -#ifdef SERVER_SUPPORT - -static void -serve_valid_requests (arg) - char *arg; -{ - struct request *rq; - if (print_pending_error ()) - return; - buf_output0 (buf_to_net, "Valid-requests"); - for (rq = requests; rq->name != NULL; rq++) - { - if (rq->func != NULL) - { - buf_append_char (buf_to_net, ' '); - buf_output0 (buf_to_net, rq->name); - } - } - buf_output0 (buf_to_net, "\nok\n"); - - /* The client is waiting for the list of valid requests, so we - must send the output now. */ - buf_flush (buf_to_net, 1); -} - -#ifdef SUNOS_KLUDGE -/* - * Delete temporary files. SIG is the signal making this happen, or - * 0 if not called as a result of a signal. - */ -static int command_pid_is_dead; -static void wait_sig (sig) - int sig; -{ - int status; - pid_t r = wait (&status); - if (r == command_pid) - command_pid_is_dead++; -} -#endif /* SUNOS_KLUDGE */ - -void -server_cleanup (sig) - int sig; -{ - /* Do "rm -rf" on the temp directory. */ - int status; - int save_noexec; - - if (buf_to_net != NULL) - { - /* Since we're done, go ahead and put BUF_TO_NET back into blocking - * mode and send any pending output. In the usual case there won't - * won't be any, but there might be if an error occured. - */ - - set_block (buf_to_net); - buf_flush (buf_to_net, 1); - - /* Next we shut down BUF_FROM_NET. That will pick up the checksum - * generated when the client shuts down its buffer. Then, after we - * have generated any final output, we shut down BUF_TO_NET. - */ - - if (buf_from_net != NULL) - { - status = buf_shutdown (buf_from_net); - if (status != 0) - error (0, status, "shutting down buffer from client"); - buf_free (buf_from_net); - buf_from_net = NULL; - } - - if (dont_delete_temp) - { - (void) buf_flush (buf_to_net, 1); - (void) buf_shutdown (buf_to_net); - buf_free (buf_to_net); - buf_to_net = NULL; - error_use_protocol = 0; - return; - } - } - else if (dont_delete_temp) - return; - - /* What a bogus kludge. This disgusting code makes all kinds of - assumptions about SunOS, and is only for a bug in that system. - So only enable it on Suns. */ -#ifdef SUNOS_KLUDGE - if (command_pid > 0) - { - /* To avoid crashes on SunOS due to bugs in SunOS tmpfs - triggered by the use of rename() in RCS, wait for the - subprocess to die. Unfortunately, this means draining output - while waiting for it to unblock the signal we sent it. Yuck! */ - int status; - pid_t r; - - signal (SIGCHLD, wait_sig); - if (sig) - /* Perhaps SIGTERM would be more correct. But the child - process will delay the SIGINT delivery until its own - children have exited. */ - kill (command_pid, SIGINT); - /* The caller may also have sent a signal to command_pid, so - always try waiting. First, though, check and see if it's still - there.... */ - do_waitpid: - r = waitpid (command_pid, &status, WNOHANG); - if (r == 0) - ; - else if (r == command_pid) - command_pid_is_dead++; - else if (r == -1) - switch (errno) - { - case ECHILD: - command_pid_is_dead++; - break; - case EINTR: - goto do_waitpid; - } - else - /* waitpid should always return one of the above values */ - abort (); - while (!command_pid_is_dead) - { - struct timeval timeout; - struct fd_set_wrapper readfds; - char buf[100]; - int i; - - /* Use a non-zero timeout to avoid eating up CPU cycles. */ - timeout.tv_sec = 2; - timeout.tv_usec = 0; - readfds = command_fds_to_drain; - switch (select (max_command_fd + 1, &readfds.fds, - (fd_set *)0, (fd_set *)0, - &timeout)) - { - case -1: - if (errno != EINTR) - abort (); - case 0: - /* timeout */ - break; - case 1: - for (i = 0; i <= max_command_fd; i++) - { - if (!FD_ISSET (i, &readfds.fds)) - continue; - /* this fd is non-blocking */ - while (read (i, buf, sizeof (buf)) >= 1) - ; - } - break; - default: - abort (); - } - } - } -#endif /* SUNOS_KLUDGE */ - - CVS_CHDIR (Tmpdir); - /* Temporarily clear noexec, so that we clean up our temp directory - regardless of it (this could more cleanly be handled by moving - the noexec check to all the unlink_file_dir callers from - unlink_file_dir itself). */ - save_noexec = noexec; - noexec = 0; - /* FIXME? Would be nice to not ignore errors. But what should we do? - We could try to do this before we shut down the network connection, - and try to notify the client (but the client might not be waiting - for responses). We could try something like syslog() or our own - log file. */ - unlink_file_dir (orig_server_temp_dir); - noexec = save_noexec; - - if (buf_to_net != NULL) - { - (void) buf_flush (buf_to_net, 1); - (void) buf_shutdown (buf_to_net); - buf_free (buf_to_net); - buf_to_net = NULL; - error_use_protocol = 0; - } -} - -int -server (argc, argv) - int argc; - char **argv; -{ - char *error_prog_name; /* Used in error messages */ - - if (argc == -1) - { - static const char *const msg[] = - { - "Usage: %s %s\n", - " Normally invoked by a cvs client on a remote machine.\n", - NULL - }; - usage (msg); - } - /* Ignore argc and argv. They might be from .cvsrc. */ - - buf_to_net = fd_buffer_initialize (STDOUT_FILENO, 0, - outbuf_memory_error); - buf_from_net = stdio_buffer_initialize (stdin, 0, 1, outbuf_memory_error); - - saved_output = buf_nonio_initialize (outbuf_memory_error); - saved_outerr = buf_nonio_initialize (outbuf_memory_error); - - /* Since we're in the server parent process, error should use the - protocol to report error messages. */ - error_use_protocol = 1; - - /* OK, now figure out where we stash our temporary files. */ - { - char *p; - - /* The code which wants to chdir into server_temp_dir is not set - up to deal with it being a relative path. So give an error - for that case. */ - if (!isabsolute (Tmpdir)) - { - 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 - does not require a client to do so. */ - } - else - { - int status; - int i = 0; - - server_temp_dir = xmalloc (strlen (Tmpdir) + 80); - if (server_temp_dir == NULL) - { - /* - * Strictly speaking, we're not supposed to output anything - * now. But we're about to exit(), give it a try. - */ - printf ("E Fatal server error, aborting.\n\ -error ENOMEM Virtual memory exhausted.\n"); - - error_exit (); - } - strcpy (server_temp_dir, Tmpdir); - - /* Remove a trailing slash from TMPDIR if present. */ - p = server_temp_dir + strlen (server_temp_dir) - 1; - if (*p == '/') - *p = '\0'; - - /* - * I wanted to use cvs-serv/PID, but then you have to worry about - * the permissions on the cvs-serv directory being right. So - * use cvs-servPID. - */ - strcat (server_temp_dir, "/cvs-serv"); - - p = server_temp_dir + strlen (server_temp_dir); - sprintf (p, "%ld", (long) getpid ()); - - orig_server_temp_dir = server_temp_dir; - - /* Create the temporary directory, and set the mode to - 700, to discourage random people from tampering with - it. */ - while ((status = mkdir_p (server_temp_dir)) == EEXIST) - { - 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 - else if (chmod (server_temp_dir, S_IRWXU) < 0) - { - int save_errno = errno; - 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; - } -#endif - else if (CVS_CHDIR (server_temp_dir) < 0) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (server_temp_dir))) - sprintf (pending_error_text, -"E cannot change to temporary directory %s", - server_temp_dir); - pending_error = save_errno; - } - } - } - - /* Now initialize our argument vector (for arguments from the client). */ - - /* Small for testing. */ - argument_vector_size = 1; - argument_vector = xmalloc (argument_vector_size * sizeof (char *)); - argument_count = 1; - /* This gets printed if the client supports an option which the - server doesn't, causing the server to print a usage message. - FIXME: just a nit, I suppose, but the usage message the server - prints isn't literally true--it suggests "cvs server" followed - by options which are for a particular command. Might be nice to - say something like "client apparently supports an option not supported - by this server" or something like that instead of usage message. */ - error_prog_name = xmalloc (strlen (program_name) + 8); - sprintf(error_prog_name, "%s server", program_name); - argument_vector[0] = error_prog_name; - - while (1) - { - char *cmd, *orig_cmd; - struct request *rq; - int status; - - status = buf_read_line (buf_from_net, &cmd, NULL); - if (status == -2) - { - buf_output0 (buf_to_net, "E Fatal server error, aborting.\n\ -error ENOMEM Virtual memory exhausted.\n"); - break; - } - if (status != 0) - break; - - orig_cmd = cmd; - for (rq = requests; rq->name != NULL; ++rq) - if (strncmp (cmd, rq->name, strlen (rq->name)) == 0) - { - int len = strlen (rq->name); - if (cmd[len] == '\0') - cmd += len; - else if (cmd[len] == ' ') - cmd += len + 1; - else - /* - * The first len characters match, but it's a different - * command. e.g. the command is "cooperate" but we matched - * "co". - */ - continue; - - if (!(rq->flags & RQ_ROOTLESS) - && current_parsed_root == NULL) - { - /* For commands which change the way in which data - is sent and received, for example Gzip-stream, - this does the wrong thing. Since the client - assumes that everything is being compressed, - unconditionally, there is no way to give this - error to the client without turning on - compression. The obvious fix would be to make - Gzip-stream RQ_ROOTLESS (with the corresponding - change to the spec), and that might be a good - idea but then again I can see some settings in - CVSROOT about what compression level to allow. - I suppose a more baroque answer would be to - turn on compression (say, at level 1), just - enough to give the "Root request missing" - error. For now we just lose. */ - if (alloc_pending (80)) - sprintf (pending_error_text, - "E Protocol error: Root request missing"); - } - else - (*rq->func) (cmd); - break; - } - if (rq->name == NULL) - { - if (!print_pending_error ()) - { - buf_output0 (buf_to_net, "error unrecognized request `"); - buf_output0 (buf_to_net, cmd); - buf_append_char (buf_to_net, '\''); - buf_append_char (buf_to_net, '\n'); - } - } - free (orig_cmd); - } - free (error_prog_name); - - /* We expect the client is done talking to us at this point. If there is - * any data in the buffer or on the network pipe, then something we didn't - * prepare for is happening. - */ - if (!buf_empty (buf_from_net)) - { - /* Try to send the error message to the client, but also syslog it, in - * case the client isn't listening anymore. - */ -#ifdef HAVE_SYSLOG_H - /* FIXME: Can the IP address of the connecting client be retrieved - * and printed here? - */ - syslog (LOG_DAEMON | LOG_ERR, "Dying gasps received from client."); -#endif - error (0, 0, "Dying gasps received from client."); - } - - /* This command will actually close the network buffers. */ - server_cleanup (0); - return 0; -} - - - -#if defined (HAVE_KERBEROS) || defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI) -static void switch_to_user PROTO((const char *, const char *)); - -static void -switch_to_user (cvs_username, username) - const char *cvs_username; /* Only used for error messages. */ - const char *username; -{ - struct passwd *pw; - - pw = getpwnam (username); - if (pw == NULL) - { - /* check_password contains a similar check, so this usually won't be - reached unless the CVS user is mapped to an invalid system user. */ - - printf ("E Fatal error, aborting.\n\ -error 0 %s: no such system user\n", username); - /* Don't worry about server_cleanup; server_active isn't set yet. */ - error_exit (); - } - - if (pw->pw_uid == 0) - { -#ifdef HAVE_SYSLOG_H - /* FIXME: Can the IP address of the connecting client be retrieved - * and printed here? - */ - syslog (LOG_DAEMON | LOG_ALERT, - "attempt to root from account: %s", cvs_username - ); -#endif - printf("error 0: root not allowed\n"); - error_exit (); - } - -#if HAVE_INITGROUPS - if (initgroups (pw->pw_name, pw->pw_gid) < 0 -# ifdef EPERM - /* At least on the system I tried, initgroups() only works as root. - But we do still want to report ENOMEM and whatever other - errors initgroups() might dish up. */ - && errno != EPERM -# endif - ) - { - /* This could be a warning, but I'm not sure I see the point - in doing that instead of an error given that it would happen - on every connection. We could log it somewhere and not tell - the user. But at least for now make it an error. */ - printf ("error 0 initgroups failed: %s\n", strerror (errno)); - /* Don't worry about server_cleanup; server_active isn't set yet. */ - error_exit (); - } -#endif /* HAVE_INITGROUPS */ - -#ifdef SETXID_SUPPORT - /* honor the setgid bit iff set*/ - if (getgid() != getegid()) - { - if (setgid (getegid ()) < 0) - { - /* See comments at setuid call below for more discussion. */ - printf ("error 0 setgid failed: %s\n", strerror (errno)); - /* Don't worry about server_cleanup; - server_active isn't set yet. */ - error_exit (); - } - } - else -#endif - { - if (setgid (pw->pw_gid) < 0) - { - /* See comments at setuid call below for more discussion. */ - printf ("error 0 setgid failed: %s\n", strerror (errno)); -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_ERR, - "setgid to %d failed (%m): real %d/%d, effective %d/%d ", - pw->pw_gid, getuid(), getgid(), geteuid(), getegid()); -#endif - /* Don't worry about server_cleanup; - server_active isn't set yet. */ - error_exit (); - } - } - - if (setuid (pw->pw_uid) < 0) - { - /* Note that this means that if run as a non-root user, - CVSROOT/passwd must contain the user we are running as - (e.g. "joe:FsEfVcu:cvs" if run as "cvs" user). This seems - cleaner than ignoring the error like CVS 1.10 and older but - it does mean that some people might need to update their - CVSROOT/passwd file. */ - printf ("error 0 setuid failed: %s\n", strerror (errno)); -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_ERR, - "setuid to %d failed (%m): real %d/%d, effective %d/%d ", - pw->pw_uid, getuid(), getgid(), geteuid(), getegid()); -#endif - /* Don't worry about server_cleanup; server_active isn't set yet. */ - error_exit (); - } - - /* We don't want our umask to change file modes. The modes should - be set by the modes used in the repository, and by the umask of - 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, USER and CVS_USER in the environment, in case they - are already set to something else. */ - { - char *env; - - env = xmalloc (sizeof "LOGNAME=" + strlen (username)); - (void) sprintf (env, "LOGNAME=%s", username); - (void) putenv (env); - - env = xmalloc (sizeof "USER=" + strlen (username)); - (void) sprintf (env, "USER=%s", username); - (void) putenv (env); - -#ifdef AUTH_SERVER_SUPPORT - env = xmalloc (sizeof "CVS_USER=" + strlen (CVS_Username)); - (void) sprintf (env, "CVS_USER=%s", CVS_Username); - (void) putenv (env); -#endif - } -#endif /* HAVE_PUTENV */ -} -#endif - -#ifdef AUTH_SERVER_SUPPORT - -extern char *crypt PROTO((const char *, const char *)); - - -/* - * 0 means no entry found for this user. - * 1 means entry found and password matches (or found password is empty) - * 2 means entry found, but password does not match. - * - * 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) - char *username, *password, *repository, **host_user_ptr; -{ - int retval = 0; - FILE *fp; - char *filename; - char *linebuf = NULL; - size_t linebuf_len; - int found_it = 0; - int namelen; - - /* We don't use current_parsed_root->directory because it hasn't been - * set yet -- our `repository' argument came from the authentication - * protocol, not the regular CVS protocol. - */ - - filename = xmalloc (strlen (repository) - + 1 - + strlen (CVSROOTADM) - + 1 - + strlen (CVSROOTADM_PASSWD) - + 1); - - (void) sprintf (filename, "%s/%s/%s", repository, - CVSROOTADM, CVSROOTADM_PASSWD); - - fp = CVS_FOPEN (filename, "r"); - if (fp == NULL) - { - if (!existence_error (errno)) - error (0, errno, "cannot open %s", filename); - free (filename); - return 0; - } - - /* Look for a relevant line -- one with this user's name. */ - namelen = strlen (username); - while (getline (&linebuf, &linebuf_len, fp) >= 0) - { - if ((strncmp (linebuf, username, namelen) == 0) - && (linebuf[namelen] == ':')) - { - found_it = 1; - break; - } - } - if (ferror (fp)) - error (0, errno, "cannot read %s", filename); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", filename); - - /* 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: <whatever>: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, ":"); - } - - /* Of course, maybe there was no system user portion... */ - if (host_user_tmp == NULL) - host_user_tmp = username; - - /* 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); - retval = 1; - } - else - { -#ifdef LOG_AUTHPRIV - syslog (LOG_AUTHPRIV | LOG_NOTICE, - "password mismatch for %s in %s: %s vs. %s", username, - repository, crypt(password, found_password), found_password); -#endif - *host_user_ptr = NULL; - retval = 2; - } - } - else /* Didn't find this user, so deny access. */ - { - *host_user_ptr = NULL; - retval = 0; - } - - free (filename); - if (linebuf) - free (linebuf); - - return retval; -} - - - -/* Return a hosting username if password matches, else NULL. */ -static char * -check_password (username, password, repository) - char *username, *password, *repository; -{ - int rc; - char *host_user = NULL; - char *found_passwd = NULL; - struct passwd *pw; - - /* First we see if this user has a password in the CVS-specific - password file. If so, that's enough to authenticate with. If - not, we'll check /etc/passwd. */ - - if (require_real_user) - rc = 0; /* "not found" */ - else - rc = check_repository_password (username, password, repository, - &host_user); - - if (rc == 2) - return NULL; - - if (rc == 1) - { - /* host_user already set by reference, so just return. */ - goto handle_return; - } - - assert (rc == 0); - - if (!system_auth) - { - /* Note that the message _does_ distinguish between the case in - which we check for a system password and the case in which - we do not. It is a real pain to track down why it isn't - letting you in if it won't say why, and I am not convinced - that the potential information disclosure to an attacker - outweighs this. */ - printf ("error 0 no such user %s in CVSROOT/passwd\n", username); - - error_exit (); - } - - /* No cvs password found, so try /etc/passwd. */ - -#ifdef HAVE_GETSPNAM - { - struct spwd *spw; - - spw = getspnam (username); - if (spw != NULL) - { - found_passwd = spw->sp_pwdp; - } - } -#endif - - if (found_passwd == NULL && (pw = getpwnam (username)) != NULL) - { - found_passwd = pw->pw_passwd; - } - - if (found_passwd == NULL) - { - printf ("E Fatal error, aborting.\n\ -error 0 %s: no such user\n", username); - - error_exit (); - } - - /* Allow for dain bramaged HPUX passwd aging - * - Basically, HPUX adds a comma and some data - * about whether the passwd has expired or not - * on the end of the passwd field. - * - This code replaces the ',' with '\0'. - * - * FIXME - our workaround is brain damaged too. I'm - * guessing that HPUX WANTED other systems to think the - * password was wrong so logins would fail if the - * system didn't handle expired passwds and the passwd - * might be expired. I think the way to go here - * is with PAM. - */ - strtok (found_passwd, ","); - - if (*found_passwd) - { - /* user exists and has a password */ - if (strcmp (found_passwd, crypt (password, found_passwd)) == 0) - { - host_user = xstrdup (username); - } - else - { - host_user = NULL; -#ifdef LOG_AUTHPRIV - syslog (LOG_AUTHPRIV | LOG_NOTICE, - "password mismatch for %s: %s vs. %s", username, - crypt(password, found_passwd), found_passwd); -#endif - } - goto handle_return; - } - - if (password && *password) - { - /* user exists and has no system password, but we got - one as parameter */ - host_user = xstrdup (username); - goto handle_return; - } - - /* user exists but has no password at all */ - host_user = NULL; -#ifdef LOG_AUTHPRIV - syslog (LOG_AUTHPRIV | LOG_NOTICE, - "login refused for %s: user has no password", username); -#endif - -handle_return: - if (host_user) - { - /* Set CVS_Username here, in allocated space. - It might or might not be the same as host_user. */ - CVS_Username = xmalloc (strlen (username) + 1); - strcpy (CVS_Username, username); - } - - return host_user; -} - -#endif /* AUTH_SERVER_SUPPORT */ - -#if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI) - -/* Read username and password from client (i.e., stdin). - If correct, then switch to run as that user and send an ACK to the - client via stdout, else send NACK and die. */ -void -pserver_authenticate_connection () -{ - char *tmp = NULL; - size_t tmp_allocated = 0; -#ifdef AUTH_SERVER_SUPPORT - char *repository = NULL; - size_t repository_allocated = 0; - char *username = NULL; - size_t username_allocated = 0; - char *password = NULL; - size_t password_allocated = 0; - - char *host_user; - char *descrambled_password; -#endif /* AUTH_SERVER_SUPPORT */ - int verify_and_exit = 0; - - /* The Authentication Protocol. Client sends: - * - * BEGIN AUTH REQUEST\n - * <REPOSITORY>\n - * <USERNAME>\n - * <PASSWORD>\n - * END AUTH REQUEST\n - * - * Server uses above information to authenticate, then sends - * - * I LOVE YOU\n - * - * if it grants access, else - * - * I HATE YOU\n - * - * if it denies access (and it exits if denying). - * - * When the client is "cvs login", the user does not desire actual - * repository access, but would like to confirm the password with - * the server. In this case, the start and stop strings are - * - * BEGIN VERIFICATION REQUEST\n - * - * and - * - * END VERIFICATION REQUEST\n - * - * On a verification request, the server's responses are the same - * (with the obvious semantics), but it exits immediately after - * sending the response in both cases. - * - * Why is the repository sent? Well, note that the actual - * client/server protocol can't start up until authentication is - * successful. But in order to perform authentication, the server - * needs to look up the password in the special CVS passwd file, - * before trying /etc/passwd. So the client transmits the - * repository as part of the "authentication protocol". The - * repository will be redundantly retransmitted later, but that's no - * big deal. - */ - -#ifdef SO_KEEPALIVE - /* Set SO_KEEPALIVE on the socket, so that we don't hang forever - if the client dies while we are waiting for input. */ - { - int on = 1; - - if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, - (char *) &on, sizeof on) < 0) - { -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_ERR, "error setting KEEPALIVE: %m"); -#endif - } - } -#endif - - /* Make sure the protocol starts off on the right foot... */ - if (getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX) < 0) - { -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_NOTICE, "bad auth protocol start: EOF"); -#endif - error (1, 0, "bad auth protocol start: EOF"); - } - - if (strcmp (tmp, "BEGIN VERIFICATION REQUEST\n") == 0) - verify_and_exit = 1; - else if (strcmp (tmp, "BEGIN AUTH REQUEST\n") == 0) - ; - else if (strcmp (tmp, "BEGIN GSSAPI REQUEST\n") == 0) - { -#ifdef HAVE_GSSAPI - free (tmp); - gserver_authenticate_connection (); - return; -#else - error (1, 0, "GSSAPI authentication not supported by this server"); -#endif - } - else - error (1, 0, "bad auth protocol start: %s", tmp); - -#ifndef AUTH_SERVER_SUPPORT - - error (1, 0, "Password authentication not supported by this server"); - -#else /* AUTH_SERVER_SUPPORT */ - - /* Get the three important pieces of information in order. */ - /* See above comment about error handling. */ - 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. - * - * We check that none of the lines were truncated by getnline in order - * to be sure that we don't accidentally allow a blind DOS attack to - * authenticate, however slim the odds of that might be. - */ - if (!strip_trailing_newlines (repository) - || !strip_trailing_newlines (username) - || !strip_trailing_newlines (password)) - error (1, 0, "Maximum line length exceeded during authentication."); - - /* ... and make sure the protocol ends on the right foot. */ - /* See above comment about error handling. */ - getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX); - if (strcmp (tmp, - verify_and_exit ? - "END VERIFICATION REQUEST\n" : "END AUTH REQUEST\n") - != 0) - { - error (1, 0, "bad auth protocol end: %s", tmp); - } - if (!root_allow_ok (repository)) - { - printf ("error 0 %s: no such repository\n", repository); -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_NOTICE, "login refused for %s", repository); -#endif - goto i_hate_you; - } - - /* OK, now parse the config file, so we can use it to control how - to check passwords. If there was an error parsing the config - file, parse_config already printed an error. We keep going. - Why? Because if we didn't, then there would be no way to check - in a new CVSROOT/config file to fix the broken one! */ - parse_config (repository); - - /* We need the real cleartext before we hash it. */ - descrambled_password = descramble (password); - host_user = check_password (username, descrambled_password, repository); - if (host_user == NULL) - { -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_NOTICE, "login failure (for %s)", repository); -#endif - memset (descrambled_password, 0, strlen (descrambled_password)); - free (descrambled_password); - i_hate_you: - printf ("I HATE YOU\n"); - fflush (stdout); - - /* Don't worry about server_cleanup, server_active isn't set - yet. */ - error_exit (); - } - memset (descrambled_password, 0, strlen (descrambled_password)); - free (descrambled_password); - - /* Don't go any farther if we're just responding to "cvs login". */ - if (verify_and_exit) - { - printf ("I LOVE YOU\n"); - fflush (stdout); - - /* It's okay to skip rcs_cleanup() and Lock_Cleanup() here. */ - -#ifdef SYSTEM_CLEANUP - /* Hook for OS-specific behavior, for example socket subsystems on - NT and OS2 or dealing with windows and arguments on Mac. */ - SYSTEM_CLEANUP (); -#endif - - exit (0); - } - - /* Set Pserver_Repos so that we can check later that the same - repository is sent in later client/server protocol. */ - Pserver_Repos = xmalloc (strlen (repository) + 1); - strcpy (Pserver_Repos, repository); - - /* Switch to run as this user. */ - switch_to_user (username, host_user); - free (host_user); - free (tmp); - free (repository); - free (username); - free (password); - - printf ("I LOVE YOU\n"); - fflush (stdout); -#endif /* AUTH_SERVER_SUPPORT */ -} - -#endif /* AUTH_SERVER_SUPPORT || HAVE_GSSAPI */ - - -#ifdef HAVE_KERBEROS -void -kserver_authenticate_connection () -{ - int status; - char instance[INST_SZ]; - struct sockaddr_in peer; - struct sockaddr_in laddr; - int len; - KTEXT_ST ticket; - AUTH_DAT auth; - char version[KRB_SENDAUTH_VLEN]; - char user[ANAME_SZ]; - - strcpy (instance, "*"); - len = sizeof peer; - if (getpeername (STDIN_FILENO, (struct sockaddr *) &peer, &len) < 0 - || getsockname (STDIN_FILENO, (struct sockaddr *) &laddr, - &len) < 0) - { - printf ("E Fatal error, aborting.\n\ -error %s getpeername or getsockname failed\n", strerror (errno)); - - error_exit (); - } - -#ifdef SO_KEEPALIVE - /* Set SO_KEEPALIVE on the socket, so that we don't hang forever - if the client dies while we are waiting for input. */ - { - int on = 1; - - if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, - (char *) &on, sizeof on) < 0) - { -#ifdef HAVE_SYSLOG_H - syslog (LOG_DAEMON | LOG_ERR, "error setting KEEPALIVE: %m"); -#endif - } - } -#endif - - status = krb_recvauth (KOPT_DO_MUTUAL, STDIN_FILENO, &ticket, "rcmd", - instance, &peer, &laddr, &auth, "", sched, - version); - if (status != KSUCCESS) - { - printf ("E Fatal error, aborting.\n\ -error 0 kerberos: %s\n", krb_get_err_text(status)); - - error_exit (); - } - - memcpy (kblock, auth.session, sizeof (C_Block)); - - /* Get the local name. */ - status = krb_kntoln (&auth, user); - if (status != KSUCCESS) - { - printf ("E Fatal error, aborting.\n\ -error 0 kerberos: can't get local name: %s\n", krb_get_err_text(status)); - - error_exit (); - } - - /* Switch to run as this user. */ - switch_to_user ("Kerberos 4", user); -} -#endif /* HAVE_KERBEROS */ - -#ifdef HAVE_GSSAPI - -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN (256) -#endif - -/* Authenticate a GSSAPI connection. This is called from - pserver_authenticate_connection, and it handles success and failure - the same way. */ - -static void -gserver_authenticate_connection () -{ - char hostname[MAXHOSTNAMELEN]; - struct hostent *hp; - gss_buffer_desc tok_in, tok_out; - char buf[1024]; - char *credbuf; - size_t credbuflen; - OM_uint32 stat_min, ret; - gss_name_t server_name, client_name; - gss_cred_id_t server_creds; - int nbytes; - gss_OID mechid; - - gethostname (hostname, sizeof hostname); - hp = gethostbyname (hostname); - if (hp == NULL) - error (1, 0, "can't get canonical hostname"); - - sprintf (buf, "cvs@%s", hp->h_name); - tok_in.value = buf; - tok_in.length = strlen (buf); - - if (gss_import_name (&stat_min, &tok_in, GSS_C_NT_HOSTBASED_SERVICE, - &server_name) != GSS_S_COMPLETE) - error (1, 0, "could not import GSSAPI service name %s", buf); - - /* Acquire the server credential to verify the client's - authentication. */ - if (gss_acquire_cred (&stat_min, server_name, 0, GSS_C_NULL_OID_SET, - GSS_C_ACCEPT, &server_creds, - NULL, NULL) != GSS_S_COMPLETE) - error (1, 0, "could not acquire GSSAPI server credentials"); - - gss_release_name (&stat_min, &server_name); - - /* The client will send us a two byte length followed by that many - bytes. */ - if (fread (buf, 1, 2, stdin) != 2) - error (1, errno, "read of length failed"); - - nbytes = ((buf[0] & 0xff) << 8) | (buf[1] & 0xff); - if (nbytes <= sizeof buf) - { - credbuf = buf; - credbuflen = sizeof buf; - } - else - { - credbuflen = nbytes; - credbuf = xmalloc (credbuflen); - } - - if (fread (credbuf, 1, nbytes, stdin) != nbytes) - error (1, errno, "read of data failed"); - - gcontext = GSS_C_NO_CONTEXT; - tok_in.length = nbytes; - tok_in.value = credbuf; - - if (gss_accept_sec_context (&stat_min, - &gcontext, /* context_handle */ - server_creds, /* verifier_cred_handle */ - &tok_in, /* input_token */ - NULL, /* channel bindings */ - &client_name, /* src_name */ - &mechid, /* mech_type */ - &tok_out, /* output_token */ - &ret, - NULL, /* ignore time_rec */ - NULL) /* ignore del_cred_handle */ - != GSS_S_COMPLETE) - { - error (1, 0, "could not verify credentials"); - } - - /* FIXME: Use Kerberos v5 specific code to authenticate to a user. - We could instead use an authentication to access mapping. */ - { - krb5_context kc; - krb5_principal p; - gss_buffer_desc desc; - - krb5_init_context (&kc); - if (gss_display_name (&stat_min, client_name, &desc, - &mechid) != GSS_S_COMPLETE - || krb5_parse_name (kc, ((gss_buffer_t) &desc)->value, &p) != 0 - || krb5_aname_to_localname (kc, p, sizeof buf, buf) != 0 - || krb5_kuserok (kc, p, buf) != TRUE) - { - error (1, 0, "access denied"); - } - krb5_free_principal (kc, p); - krb5_free_context (kc); - } - - if (tok_out.length != 0) - { - char cbuf[2]; - - cbuf[0] = (tok_out.length >> 8) & 0xff; - cbuf[1] = tok_out.length & 0xff; - if (fwrite (cbuf, 1, 2, stdout) != 2 - || (fwrite (tok_out.value, 1, tok_out.length, stdout) - != tok_out.length)) - error (1, errno, "fwrite failed"); - } - - switch_to_user ("GSSAPI", buf); - - if (credbuf != buf) - free (credbuf); - - printf ("I LOVE YOU\n"); - fflush (stdout); -} - -#endif /* HAVE_GSSAPI */ - -#endif /* SERVER_SUPPORT */ - -#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) - -/* This global variable is non-zero if the user requests encryption on - the command line. */ -int cvsencrypt; - -/* This global variable is non-zero if the users requests stream - authentication on the command line. */ -int cvsauthenticate; - -#ifdef HAVE_GSSAPI - -/* An buffer interface using GSSAPI. This is built on top of a - packetizing buffer. */ - -/* This structure is the closure field of the GSSAPI translation - routines. */ - -struct cvs_gssapi_wrap_data -{ - /* The GSSAPI context. */ - gss_ctx_id_t gcontext; -}; - -static int cvs_gssapi_wrap_input PROTO((void *, const char *, char *, int)); -static int cvs_gssapi_wrap_output PROTO((void *, const char *, char *, int, - int *)); - -/* Create a GSSAPI wrapping buffer. We use a packetizing buffer with - GSSAPI wrapping routines. */ - -struct buffer * -cvs_gssapi_wrap_buffer_initialize (buf, input, gcontext, memory) - struct buffer *buf; - int input; - gss_ctx_id_t gcontext; - void (*memory) PROTO((struct buffer *)); -{ - struct cvs_gssapi_wrap_data *gd; - - gd = (struct cvs_gssapi_wrap_data *) xmalloc (sizeof *gd); - gd->gcontext = gcontext; - - return (packetizing_buffer_initialize - (buf, - input ? cvs_gssapi_wrap_input : NULL, - input ? NULL : cvs_gssapi_wrap_output, - gd, - memory)); -} - -/* Unwrap data using GSSAPI. */ - -static int -cvs_gssapi_wrap_input (fnclosure, input, output, size) - void *fnclosure; - const char *input; - char *output; - int size; -{ - struct cvs_gssapi_wrap_data *gd = - (struct cvs_gssapi_wrap_data *) fnclosure; - gss_buffer_desc inbuf, outbuf; - OM_uint32 stat_min; - int conf; - - inbuf.value = (void *) input; - inbuf.length = size; - - if (gss_unwrap (&stat_min, gd->gcontext, &inbuf, &outbuf, &conf, NULL) - != GSS_S_COMPLETE) - { - error (1, 0, "gss_unwrap failed"); - } - - if (outbuf.length > size) - abort (); - - memcpy (output, outbuf.value, outbuf.length); - - /* The real packet size is stored in the data, so we don't need to - remember outbuf.length. */ - - gss_release_buffer (&stat_min, &outbuf); - - return 0; -} - -/* Wrap data using GSSAPI. */ - -static int -cvs_gssapi_wrap_output (fnclosure, input, output, size, translated) - void *fnclosure; - const char *input; - char *output; - int size; - int *translated; -{ - struct cvs_gssapi_wrap_data *gd = - (struct cvs_gssapi_wrap_data *) fnclosure; - gss_buffer_desc inbuf, outbuf; - OM_uint32 stat_min; - int conf_req, conf; - - inbuf.value = (void *) input; - inbuf.length = size; - -#ifdef ENCRYPTION - conf_req = cvs_gssapi_encrypt; -#else - conf_req = 0; -#endif - - if (gss_wrap (&stat_min, gd->gcontext, conf_req, GSS_C_QOP_DEFAULT, - &inbuf, &conf, &outbuf) != GSS_S_COMPLETE) - error (1, 0, "gss_wrap failed"); - - /* The packetizing buffer only permits us to add 100 bytes. - FIXME: I don't know what, if anything, is guaranteed by GSSAPI. - This may need to be increased for a different GSSAPI - implementation, or we may need a different algorithm. */ - if (outbuf.length > size + 100) - abort (); - - memcpy (output, outbuf.value, outbuf.length); - - *translated = outbuf.length; - - gss_release_buffer (&stat_min, &outbuf); - - return 0; -} - -#endif /* HAVE_GSSAPI */ - -#ifdef ENCRYPTION - -#ifdef HAVE_KERBEROS - -/* An encryption interface using Kerberos. This is built on top of a - packetizing buffer. */ - -/* This structure is the closure field of the Kerberos translation - routines. */ - -struct krb_encrypt_data -{ - /* The Kerberos key schedule. */ - Key_schedule sched; - /* The Kerberos DES block. */ - C_Block block; -}; - -static int krb_encrypt_input PROTO((void *, const char *, char *, int)); -static int krb_encrypt_output PROTO((void *, const char *, char *, int, - int *)); - -/* Create a Kerberos encryption buffer. We use a packetizing buffer - with Kerberos encryption translation routines. */ - -struct buffer * -krb_encrypt_buffer_initialize (buf, input, sched, block, memory) - struct buffer *buf; - int input; - Key_schedule sched; - C_Block block; - void (*memory) PROTO((struct buffer *)); -{ - struct krb_encrypt_data *kd; - - kd = (struct krb_encrypt_data *) xmalloc (sizeof *kd); - memcpy (kd->sched, sched, sizeof (Key_schedule)); - memcpy (kd->block, block, sizeof (C_Block)); - - return packetizing_buffer_initialize (buf, - input ? krb_encrypt_input : NULL, - input ? NULL : krb_encrypt_output, - kd, - memory); -} - -/* Decrypt Kerberos data. */ - -static int -krb_encrypt_input (fnclosure, input, output, size) - void *fnclosure; - const char *input; - char *output; - int size; -{ - struct krb_encrypt_data *kd = (struct krb_encrypt_data *) fnclosure; - int tcount; - - des_cbc_encrypt ((C_Block *) input, (C_Block *) output, - size, kd->sched, &kd->block, 0); - - /* SIZE is the size of the buffer, which is set by the encryption - routine. The packetizing buffer will arrange for the first two - bytes in the decrypted buffer to be the real (unaligned) - length. As a safety check, make sure that the length in the - buffer corresponds to SIZE. Note that the length in the buffer - is just the length of the data. We must add 2 to account for - the buffer count itself. */ - tcount = ((output[0] & 0xff) << 8) + (output[1] & 0xff); - if (((tcount + 2 + 7) & ~7) != size) - error (1, 0, "Decryption failure"); - - return 0; -} - -/* Encrypt Kerberos data. */ - -static int -krb_encrypt_output (fnclosure, input, output, size, translated) - void *fnclosure; - const char *input; - char *output; - int size; - int *translated; -{ - struct krb_encrypt_data *kd = (struct krb_encrypt_data *) fnclosure; - int aligned; - - /* For security against a known plaintext attack, we should - initialize any padding bytes to random values. Instead, we - just pick up whatever is on the stack, which is at least better - than using zero. */ - - /* Align SIZE to an 8 byte boundary. Note that SIZE includes the - two byte buffer count at the start of INPUT which was added by - the packetizing buffer. */ - aligned = (size + 7) & ~7; - - /* We use des_cbc_encrypt rather than krb_mk_priv because the - latter sticks a timestamp in the block, and krb_rd_priv expects - that timestamp to be within five minutes of the current time. - Given the way the CVS server buffers up data, that can easily - fail over a long network connection. We trust krb_recvauth to - guard against a replay attack. */ - - des_cbc_encrypt ((C_Block *) input, (C_Block *) output, aligned, - kd->sched, &kd->block, 1); - - *translated = aligned; - - return 0; -} - -#endif /* HAVE_KERBEROS */ -#endif /* ENCRYPTION */ -#endif /* defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) */ - -/* Output LEN bytes at STR. If LEN is zero, then output up to (not including) - the first '\0' byte. */ - -void -cvs_output (str, len) - const char *str; - size_t len; -{ - if (len == 0) - len = strlen (str); -#ifdef SERVER_SUPPORT - if (error_use_protocol && buf_to_net != NULL) - { - buf_output (saved_output, str, len); - buf_copy_lines (buf_to_net, saved_output, 'M'); - } - else if (server_active && protocol != NULL) - { - buf_output (saved_output, str, len); - buf_copy_lines (protocol, saved_output, 'M'); - buf_send_counted (protocol); - } - else -#endif - { - size_t written; - size_t to_write = len; - const char *p = str; - - /* Local users that do 'cvs status 2>&1' on a local repository - may see the informational messages out-of-order with the - status messages unless we use the fflush (stderr) here. */ - fflush (stderr); - - while (to_write > 0) - { - written = fwrite (p, 1, to_write, stdout); - if (written == 0) - break; - p += written; - to_write -= written; - } - } -} - -/* Output LEN bytes at STR in binary mode. If LEN is zero, then - output zero bytes. */ - -void -cvs_output_binary (str, len) - char *str; - size_t len; -{ -#ifdef SERVER_SUPPORT - if (error_use_protocol || server_active) - { - struct buffer *buf; - char size_text[40]; - - if (error_use_protocol) - buf = buf_to_net; - else - buf = protocol; - - if (!supported_response ("Mbinary")) - { - error (0, 0, "\ -this client does not support writing binary files to stdout"); - return; - } - - buf_output0 (buf, "Mbinary\012"); - sprintf (size_text, "%lu\012", (unsigned long) len); - buf_output0 (buf, size_text); - - /* Not sure what would be involved in using buf_append_data here - without stepping on the toes of our caller (which is responsible - for the memory allocation of STR). */ - buf_output (buf, str, len); - - if (!error_use_protocol) - buf_send_counted (protocol); - } - else -#endif - { - size_t written; - size_t to_write = len; - const char *p = str; -#ifdef USE_SETMODE_STDOUT - int oldmode; -#endif - - /* Local users that do 'cvs status 2>&1' on a local repository - may see the informational messages out-of-order with the - status messages unless we use the fflush (stderr) here. */ - fflush (stderr); - -#ifdef USE_SETMODE_STDOUT - /* It is possible that this should be the same ifdef as - USE_SETMODE_BINARY but at least for the moment we keep them - separate. Mostly this is just laziness and/or a question - of what has been tested where. Also there might be an - issue of setmode vs. _setmode. */ - /* The Windows doc says to call setmode only right after startup. - I assume that what they are talking about can also be helped - by flushing the stream before changing the mode. */ - fflush (stdout); - oldmode = _setmode (_fileno (stdout), OPEN_BINARY); - if (oldmode < 0) - error (0, errno, "failed to setmode on stdout"); -#endif - - while (to_write > 0) - { - written = fwrite (p, 1, to_write, stdout); - if (written == 0) - break; - p += written; - to_write -= written; - } -#ifdef USE_SETMODE_STDOUT - fflush (stdout); - if (_setmode (_fileno (stdout), oldmode) != OPEN_BINARY) - error (0, errno, "failed to setmode on stdout"); -#endif - } -} - - - -/* Like CVS_OUTPUT but output is for stderr not stdout. */ -void -cvs_outerr (str, len) - const char *str; - size_t len; -{ - if (len == 0) - len = strlen (str); -#ifdef SERVER_SUPPORT - if (error_use_protocol) - { - buf_output (saved_outerr, str, len); - buf_copy_lines (buf_to_net, saved_outerr, 'E'); - } - else if (server_active) - { - buf_output (saved_outerr, str, len); - buf_copy_lines (protocol, saved_outerr, 'E'); - buf_send_counted (protocol); - } - else -#endif - { - size_t written; - size_t to_write = len; - const char *p = str; - - /* Make sure that output appears in order if stdout and stderr - point to the same place. For the server case this is taken - care of by the fact that saved_outerr always holds less - than a line. */ - fflush (stdout); - - while (to_write > 0) - { - written = fwrite (p, 1, to_write, stderr); - if (written == 0) - break; - p += written; - to_write -= written; - } - } -} - - - -/* Flush stderr. stderr is normally flushed automatically, of course, - but this function is used to flush information from the server back - to the client. */ -void -cvs_flusherr () -{ -#ifdef SERVER_SUPPORT - if (error_use_protocol) - { - /* skip the actual stderr flush in this case since the parent process - * on the server should only be writing to stdout anyhow - */ - /* Flush what we can to the network, but don't block. */ - buf_flush (buf_to_net, 0); - } - else if (server_active) - { - /* make sure stderr is flushed before we send the flush count on the - * protocol pipe - */ - fflush (stderr); - /* Send a special count to tell the parent to flush. */ - buf_send_special_count (protocol, -2); - } - else -#endif - fflush (stderr); -} - - - -/* Make it possible for the user to see what has been written to - stdout (it is up to the implementation to decide exactly how far it - should go to ensure this). */ -void -cvs_flushout () -{ -#ifdef SERVER_SUPPORT - if (error_use_protocol) - { - /* Flush what we can to the network, but don't block. */ - buf_flush (buf_to_net, 0); - } - else if (server_active) - { - /* Just do nothing. This is because the code which - cvs_flushout replaces, setting stdout to line buffering in - main.c, didn't get called in the server child process. But - in the future it is quite plausible that we'll want to make - this case work analogously to cvs_flusherr. - - FIXME - DRP - I tried to implement this and triggered the following - error: "Protocol error: uncounted data discarded". I don't need - this feature right now, so I'm not going to bother with it yet. - */ - buf_send_special_count (protocol, -1); - } - else -#endif - fflush (stdout); -} - -/* Output TEXT, tagging it according to TAG. There are lots more - details about what TAG means in cvsclient.texi but for the simple - case (e.g. non-client/server), TAG is just "newline" to output a - newline (in which case TEXT must be NULL), and any other tag to - output normal text. - - Note that there is no way to output either \0 or \n as part of TEXT. */ - -void -cvs_output_tagged (tag, text) - const char *tag; - const char *text; -{ - if (text != NULL && strchr (text, '\n') != NULL) - /* Uh oh. The protocol has no way to cope with this. For now - we dump core, although that really isn't such a nice - response given that this probably can be caused by newlines - in filenames and other causes other than bugs in CVS. Note - that we don't want to turn this into "MT newline" because - this case is a newline within a tagged item, not a newline - as extraneous sugar for the user. */ - assert (0); - - /* Start and end tags don't take any text, per cvsclient.texi. */ - if (tag[0] == '+' || tag[0] == '-') - assert (text == NULL); - -#ifdef SERVER_SUPPORT - if (server_active && supported_response ("MT")) - { - struct buffer *buf; - - if (error_use_protocol) - buf = buf_to_net; - else - buf = protocol; - - buf_output0 (buf, "MT "); - buf_output0 (buf, tag); - if (text != NULL) - { - buf_output (buf, " ", 1); - buf_output0 (buf, text); - } - buf_output (buf, "\n", 1); - - if (!error_use_protocol) - buf_send_counted (protocol); - } - else -#endif - { - if (strcmp (tag, "newline") == 0) - cvs_output ("\n", 1); - else if (text != NULL) - cvs_output (text, 0); - } -} diff --git a/contrib/cvs/src/server.h b/contrib/cvs/src/server.h deleted file mode 100644 index 4c32386..0000000 --- a/contrib/cvs/src/server.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS kit. - * - * - * - * This file contains the interface between the server and the rest of CVS. - */ - -/* Miscellaneous stuff which isn't actually particularly server-specific. */ -#ifndef STDIN_FILENO -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 -#endif - - -/* - * Nonzero if we are using the server. Used by various places to call - * server-specific functions. - */ -extern int server_active; - -/* - * Expand to `S', ` ', or the empty string. Used in `%s-> ...' trace printfs. - */ -#ifdef SERVER_SUPPORT -# define CLIENT_SERVER_STR ((server_active) ? "S" : " ") -#else -# define CLIENT_SERVER_STR "" -#endif - -#ifdef SERVER_SUPPORT - -/* Server functions exported to the rest of CVS. */ - -/* Run the server. */ -extern int server PROTO((int argc, char **argv)); - -/* kserver user authentication. */ -# ifdef HAVE_KERBEROS -extern void kserver_authenticate_connection PROTO ((void)); -# endif - -/* pserver user authentication. */ -# if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI) -extern void pserver_authenticate_connection PROTO ((void)); -# endif - -/* See server.c for description. */ -extern void server_pathname_check PROTO ((char *)); - -/* We have a new Entries line for a file. TAG or DATE can be NULL. */ -extern void server_register - PROTO((const char *name, const char *version, const char *timestamp, - const char *options, const char *tag, const char *date, - const char *conflict)); - -/* Set the modification time of the next file sent. This must be - followed by a call to server_updated on the same file. */ -extern void server_modtime PROTO ((struct file_info *finfo, - Vers_TS *vers_ts)); - -/* - * We want to nuke the Entries line for a file, and (unless - * server_scratch_entry_only is subsequently called) the file itself. - */ -extern void server_scratch PROTO((const char *name)); - -/* - * The file which just had server_scratch called on it needs to have only - * the Entries line removed, not the file itself. - */ -extern void server_scratch_entry_only PROTO((void)); - -/* - * We just successfully checked in FILE (which is just the bare - * filename, with no directory). REPOSITORY is the directory for the - * repository. - */ -extern void server_checked_in - PROTO((const char *file, const char *update_dir, const char *repository)); - -extern void server_copy_file - PROTO((const char *file, const char *update_dir, const char *repository, - const char *newfile)); - -/* Send the appropriate responses for a file described by FINFO and - VERS. This is called after server_register or server_scratch. In - the latter case the file is to be removed (and VERS can be NULL). - In the former case, VERS must be non-NULL, and UPDATED indicates - whether the file is now up to date (SERVER_UPDATED, yes, - SERVER_MERGED, no, SERVER_PATCHED, yes, but file is a diff from - user version to repository version, SERVER_RCS_DIFF, yes, like - SERVER_PATCHED but with an RCS style diff). MODE is the mode the - file should get, or (mode_t) -1 if this should be obtained from the - file itself. CHECKSUM is the MD5 checksum of the file, or NULL if - this need not be sent. If FILEBUF is not NULL, it holds the - contents of the file, in which case the file itself may not exist. - If FILEBUF is not NULL, server_updated will free it. */ -enum server_updated_arg4 -{ - SERVER_UPDATED, - SERVER_MERGED, - SERVER_PATCHED, - SERVER_RCS_DIFF -}; -#ifdef __STDC__ -struct buffer; -#endif - -extern void server_updated - PROTO((struct file_info *finfo, Vers_TS *vers, - enum server_updated_arg4 updated, mode_t mode, - unsigned char *checksum, struct buffer *filebuf)); - -/* Whether we should send RCS format patches. */ -extern int server_use_rcs_diff PROTO((void)); - -/* Set the Entries.Static flag. */ -extern void server_set_entstat PROTO((const char *update_dir, - const char *repository)); -/* Clear it. */ -extern void server_clear_entstat PROTO((const char *update_dir, - const char *repository)); - -/* Set or clear a per-directory sticky tag or date. */ -extern void server_set_sticky PROTO((const char *update_dir, - const char *repository, const char *tag, - const char *date, int nonbranch)); -/* Send Template response. */ -extern void server_template PROTO ((const char *, const char *)); - -extern void server_update_entries - PROTO((const char *file, const char *update_dir, const char *repository, - enum server_updated_arg4 updated)); - -/* Pointer to a malloc'd string which is the directory which - the server should prepend to the pathnames which it sends - to the client. */ -extern char *server_dir; - -extern void server_cleanup PROTO((int sig)); - -#ifdef SERVER_FLOWCONTROL -/* Pause if it's convenient to avoid memory blowout */ -extern void server_pause_check PROTO((void)); -#endif /* SERVER_FLOWCONTROL */ - -#ifdef AUTH_SERVER_SUPPORT -extern char *CVS_Username; -extern int system_auth; -#endif /* AUTH_SERVER_SUPPORT */ - -#endif /* SERVER_SUPPORT */ - -/* Stuff shared with the client. */ -struct request -{ - /* Name of the request. */ - char *name; - -#ifdef SERVER_SUPPORT - /* - * Function to carry out the request. ARGS is the text of the command - * after name and, if present, a single space, have been stripped off. - */ - void (*func) PROTO((char *args)); -#endif - - /* One or more of the RQ_* flags described below. */ - int flags; - - /* If set, failure to implement this request can imply a fatal - error. This should be set only for commands which were in the - original version of the protocol; it should not be set for new - commands. */ -#define RQ_ESSENTIAL 1 - - /* Set by the client if the server we are talking to supports it. */ -#define RQ_SUPPORTED 2 - - /* If set, and client and server both support the request, the - client should tell the server by making the request. */ -#define RQ_ENABLEME 4 - - /* The server may accept this request before "Root". */ -#define RQ_ROOTLESS 8 -}; - -/* Table of requests ending with an entry with a NULL name. */ -extern struct request requests[]; - -/* Gzip library, see zlib.c. */ -extern int gunzip_and_write PROTO ((int, char *, unsigned char *, size_t)); -extern int read_and_gzip PROTO ((int, const char *, unsigned char **, size_t *, - size_t *, int)); diff --git a/contrib/cvs/src/stack.c b/contrib/cvs/src/stack.c deleted file mode 100644 index 22a1088..0000000 --- a/contrib/cvs/src/stack.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2004-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 2004-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * This module uses the hash.c module to implement a stack. - */ - -#include "cvs.h" -#include <assert.h> - - - -static void -do_push (stack, elem, isstring) - List *stack; - void *elem; - int isstring; -{ - Node *p = getnode(); - - if (isstring) - p->key = elem; - else - p->data = elem; - - addnode(stack, p); -} - - - -void -push (stack, elem) - List *stack; - void *elem; -{ - do_push (stack, elem, 0); -} - - - -void -push_string (stack, elem) - List *stack; - char *elem; -{ - do_push (stack, elem, 1); -} - - - -static void * -do_pop (stack, isstring) - List *stack; - int isstring; -{ - void *elem; - - if (isempty (stack)) return NULL; - - if (isstring) - { - elem = stack->list->prev->key; - stack->list->prev->key = NULL; - } - else - { - elem = stack->list->prev->data; - stack->list->prev->data = NULL; - } - - delnode (stack->list->prev); - return elem; -} - - - -void * -pop (stack) - List *stack; -{ - return do_pop (stack, 0); -} - - - -char * -pop_string (stack) - List *stack; -{ - return do_pop (stack, 1); -} - - - -static void -do_unshift (stack, elem, isstring) - List *stack; - void *elem; - int isstring; -{ - Node *p = getnode(); - - if (isstring) - p->key = elem; - else - p->data = elem; - - addnode_at_front(stack, p); -} - - - -void -unshift (stack, elem) - List *stack; - void *elem; -{ - do_unshift (stack, elem, 0); -} - - - -void -unshift_string (stack, elem) - List *stack; - char *elem; -{ - do_unshift (stack, elem, 1); -} - - - -static void * -do_shift (stack, isstring) - List *stack; - int isstring; -{ - void *elem; - - if (isempty (stack)) return NULL; - - if (isstring) - { - elem = stack->list->next->key; - stack->list->next->key = NULL; - } - else - { - elem = stack->list->next->data; - stack->list->next->data = NULL; - } - delnode (stack->list->next); - return elem; -} - - - -void * -shift (stack) - List *stack; -{ - return do_shift (stack, 0); -} - - - -char * -shift_string (stack) - List *stack; -{ - return do_shift (stack, 1); -} - - - -int -isempty (stack) - List *stack; -{ - if (stack->list == stack->list->next) - return 1; - return 0; -} diff --git a/contrib/cvs/src/stack.h b/contrib/cvs/src/stack.h deleted file mode 100644 index 822010b..0000000 --- a/contrib/cvs/src/stack.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Free Software Foundation, - * Derek Price, and Ximbiot <http://ximbiot.com>. - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - */ - -void push PROTO((List *_stack, void *_elem)); -void *pop PROTO((List *_stack)); -void unshift PROTO((List *_stack, void *_elem)); -void *shift PROTO((List *_stack)); -void push_string PROTO((List *_stack, char *_elem)); -char *pop_string PROTO((List *_stack)); -void unshift_string PROTO((List *_stack, char *_elem)); -char *shift_string PROTO((List *_stack)); -int isempty PROTO((List *_stack)); diff --git a/contrib/cvs/src/status.c b/contrib/cvs/src/status.c deleted file mode 100644 index 7a828ae..0000000 --- a/contrib/cvs/src/status.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Status Information - */ - -#include "cvs.h" - -static Dtype status_dirproc PROTO ((void *callerdat, const char *dir, - const char *repos, const char *update_dir, - List *entries)); -static int status_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static int tag_list_proc PROTO((Node * p, void *closure)); - -static int local = 0; -static int long_format = 0; -static RCSNode *xrcsnode; - -static const char *const status_usage[] = -{ - "Usage: %s %s [-vlR] [files...]\n", - "\t-v\tVerbose format; includes tag information for the file\n", - "\t-l\tProcess this directory only (not recursive).\n", - "\t-R\tProcess directories recursively.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -int -cvsstatus (argc, argv) - int argc; - char **argv; -{ - int c; - int err = 0; - - if (argc == -1) - usage (status_usage); - - optind = 0; - while ((c = getopt (argc, argv, "+vlR")) != -1) - { - switch (c) - { - case 'v': - long_format = 1; - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case '?': - default: - usage (status_usage); - break; - } - } - argc -= optind; - argv += optind; - - wrap_setup (); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - start_server (); - - ign_setup (); - - if (long_format) - send_arg("-v"); - if (local) - send_arg("-l"); - send_arg ("--"); - - /* For a while, we tried setting SEND_NO_CONTENTS here so this - could be a fast operation. That prevents the - server from updating our timestamp if the timestamp is - changed but the file is unmodified. Worse, it is user-visible - (shows "locally modified" instead of "up to date" if - timestamp is changed but file is not). And there is no good - workaround (you might not want to run "cvs update"; "cvs -n - update" doesn't update CVS/Entries; "cvs diff --brief" or - something perhaps could be made to work but somehow that - seems nonintuitive to me even if so). Given that timestamps - seem to have the potential to get munged for any number of - reasons, it seems better to not rely too much on them. */ - - send_files (argc, argv, local, 0, 0); - - send_file_names (argc, argv, SEND_EXPAND_WILD); - - send_to_server ("status\012", 0); - err = get_responses_and_close (); - - return err; - } -#endif - - /* start the recursion processor */ - err = start_recursion (status_fileproc, (FILESDONEPROC) NULL, - status_dirproc, (DIRLEAVEPROC) NULL, NULL, - argc, argv, local, - W_LOCAL, 0, CVS_LOCK_READ, (char *) NULL, 1, - (char *) NULL); - - return (err); -} - -/* - * display the status of a file - */ -/* ARGSUSED */ -static int -status_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - Ctype status; - char *sstat; - Vers_TS *vers; - - status = Classify_File (finfo, (char *) NULL, (char *) NULL, (char *) NULL, - 1, 0, &vers, 0); - sstat = "Classify Error"; - switch (status) - { - case T_UNKNOWN: - sstat = "Unknown"; - break; - case T_CHECKOUT: - sstat = "Needs Checkout"; - break; - case T_PATCH: - sstat = "Needs Patch"; - break; - case T_CONFLICT: - sstat = "Unresolved Conflict"; - break; - case T_ADDED: - sstat = "Locally Added"; - break; - case T_REMOVED: - sstat = "Locally Removed"; - break; - case T_MODIFIED: - if (file_has_markers (finfo)) - sstat = "File had conflicts on merge"; - else - /* Note that we do not re Register() the file when we spot - * a resolved conflict like update_fileproc() does on the - * premise that status should not alter the sandbox. - */ - sstat = "Locally Modified"; - break; - case T_REMOVE_ENTRY: - sstat = "Entry Invalid"; - break; - case T_UPTODATE: - sstat = "Up-to-date"; - break; - case T_NEEDS_MERGE: - sstat = "Needs Merge"; - break; - case T_TITLE: - /* I don't think this case can occur here. Just print - "Classify Error". */ - break; - } - - cvs_output ("\ -===================================================================\n", 0); - if (vers->ts_user == NULL) - { - cvs_output ("File: no file ", 0); - cvs_output (finfo->file, 0); - cvs_output ("\t\tStatus: ", 0); - cvs_output (sstat, 0); - cvs_output ("\n\n", 0); - } - else - { - char *buf; - buf = xmalloc (strlen (finfo->file) + strlen (sstat) + 80); - sprintf (buf, "File: %-17s\tStatus: %s\n\n", finfo->file, sstat); - cvs_output (buf, 0); - free (buf); - } - - if (vers->vn_user == NULL) - { - cvs_output (" Working revision:\tNo entry for ", 0); - cvs_output (finfo->file, 0); - cvs_output ("\n", 0); - } - else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') - cvs_output (" Working revision:\tNew file!\n", 0); - else - { - cvs_output (" Working revision:\t", 0); - cvs_output (vers->vn_user, 0); - if (!server_active) - { - cvs_output ("\t", 0); - cvs_output (vers->ts_rcs, 0); - } - cvs_output ("\n", 0); - } - - if (vers->vn_rcs == NULL) - cvs_output (" Repository revision:\tNo revision control file\n", 0); - else - { - cvs_output (" Repository revision:\t", 0); - cvs_output (vers->vn_rcs, 0); - cvs_output ("\t", 0); - cvs_output (vers->srcfile->path, 0); - cvs_output ("\n", 0); - } - - if (vers->entdata) - { - Entnode *edata; - - edata = vers->entdata; - if (edata->tag) - { - if (vers->vn_rcs == NULL) - { - cvs_output (" Sticky Tag:\t\t", 0); - cvs_output (edata->tag, 0); - cvs_output (" - MISSING from RCS file!\n", 0); - } - else - { - if (isdigit ((unsigned char) edata->tag[0])) - { - cvs_output (" Sticky Tag:\t\t", 0); - cvs_output (edata->tag, 0); - cvs_output ("\n", 0); - } - else - { - char *branch = NULL; - - if (RCS_nodeisbranch (finfo->rcs, edata->tag)) - branch = RCS_whatbranch(finfo->rcs, edata->tag); - - cvs_output (" Sticky Tag:\t\t", 0); - cvs_output (edata->tag, 0); - cvs_output (" (", 0); - cvs_output (branch ? "branch" : "revision", 0); - cvs_output (": ", 0); - cvs_output (branch ? branch : vers->vn_rcs, 0); - cvs_output (")\n", 0); - - if (branch) - free (branch); - } - } - } - else if (!really_quiet) - cvs_output (" Sticky Tag:\t\t(none)\n", 0); - - if (edata->date) - { - cvs_output (" Sticky Date:\t\t", 0); - cvs_output (edata->date, 0); - cvs_output ("\n", 0); - } - else if (!really_quiet) - cvs_output (" Sticky Date:\t\t(none)\n", 0); - - if (edata->options && edata->options[0]) - { - cvs_output (" Sticky Options:\t", 0); - cvs_output (edata->options, 0); - cvs_output ("\n", 0); - } - else if (!really_quiet) - cvs_output (" Sticky Options:\t(none)\n", 0); - } - - if (long_format && vers->srcfile) - { - List *symbols = RCS_symbols(vers->srcfile); - - cvs_output ("\n Existing Tags:\n", 0); - if (symbols) - { - xrcsnode = finfo->rcs; - (void) walklist (symbols, tag_list_proc, NULL); - } - else - cvs_output ("\tNo Tags Exist\n", 0); - } - - cvs_output ("\n", 0); - freevers_ts (&vers); - return (0); -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -status_dirproc (callerdat, dir, repos, update_dir, entries) - void *callerdat; - const char *dir; - const char *repos; - const char *update_dir; - List *entries; -{ - if (!quiet) - error (0, 0, "Examining %s", update_dir); - return (R_PROCESS); -} - -/* - * Print out a tag and its type - */ -static int -tag_list_proc (p, closure) - Node *p; - void *closure; -{ - char *branch = NULL; - char *buf; - - if (RCS_nodeisbranch (xrcsnode, p->key)) - branch = RCS_whatbranch(xrcsnode, p->key) ; - - buf = xmalloc (80 + strlen (p->key) - + (branch ? strlen (branch) : strlen (p->data))); - sprintf (buf, "\t%-25s\t(%s: %s)\n", p->key, - branch ? "branch" : "revision", - branch ? branch : (char *)p->data); - cvs_output (buf, 0); - free (buf); - - if (branch) - free (branch); - - return (0); -} diff --git a/contrib/cvs/src/subr.c b/contrib/cvs/src/subr.c deleted file mode 100644 index faa988a..0000000 --- a/contrib/cvs/src/subr.c +++ /dev/null @@ -1,968 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Various useful functions for the CVS support code. - */ - -#include <assert.h> -#include "cvs.h" -#include "getline.h" - -#ifdef HAVE_NANOSLEEP -# include "xtime.h" -#else /* HAVE_NANOSLEEP */ -# if !defined HAVE_USLEEP && defined HAVE_SELECT - /* use select as a workaround */ -# include "xselect.h" -# endif /* !defined HAVE_USLEEP && defined HAVE_SELECT */ -#endif /* !HAVE_NANOSLEEP */ - -extern char *getlogin (); - -/* - * malloc some data and die if it fails - */ -void * -xmalloc (bytes) - size_t bytes; -{ - char *cp; - - /* Parts of CVS try to xmalloc zero bytes and then free it. Some - systems have a malloc which returns NULL for zero byte - allocations but a free which can't handle NULL, so compensate. */ - if (bytes == 0) - bytes = 1; - - cp = malloc (bytes); - if (cp == NULL) - { - char buf[80]; - sprintf (buf, "out of memory; can not allocate %lu bytes", - (unsigned long) bytes); - error (1, 0, buf); - } - return (cp); -} - -/* - * realloc data and die if it fails [I've always wanted to have "realloc" do - * a "malloc" if the argument is NULL, but you can't depend on it. Here, I - * can *force* it.] - */ -void * -xrealloc (ptr, bytes) - void *ptr; - size_t bytes; -{ - char *cp; - - if (!ptr) - cp = malloc (bytes); - else - cp = realloc (ptr, bytes); - - if (cp == NULL) - { - char buf[80]; - sprintf (buf, "out of memory; can not reallocate %lu bytes", - (unsigned long) bytes); - error (1, 0, buf); - } - return (cp); -} - -/* Two constants which tune expand_string. Having MIN_INCR as large - as 1024 might waste a bit of memory, but it shouldn't be too bad - (CVS used to allocate arrays of, say, 3000, PATH_MAX (8192, often), - or other such sizes). Probably anything which is going to allocate - memory which is likely to get as big as MAX_INCR shouldn't be doing - it in one block which must be contiguous, but since getrcskey does - so, we might as well limit the wasted memory to MAX_INCR or so - bytes. - - MIN_INCR and MAX_INCR should both be powers of two and we generally - try to keep our allocations to powers of two for the most part. - Most malloc implementations these days tend to like that. */ - -#define MIN_INCR 1024 -#define MAX_INCR (2*1024*1024) - -/* *STRPTR is a pointer returned from malloc (or NULL), pointing to *N - characters of space. Reallocate it so that points to at least - NEWSIZE bytes of space. Gives a fatal error if out of memory; - if it returns it was successful. */ -void -expand_string (strptr, n, newsize) - char **strptr; - size_t *n; - size_t newsize; -{ - if (*n < newsize) - { - while (*n < newsize) - { - if (*n < MIN_INCR) - *n = MIN_INCR; - else if (*n >= MAX_INCR) - *n += MAX_INCR; - else - { - *n *= 2; - if (*n > MAX_INCR) - *n = MAX_INCR; - } - } - *strptr = xrealloc (*strptr, *n); - } -} - -/* *STR is a pointer to a malloc'd string. *LENP is its allocated - length. Add SRC to the end of it, reallocating if necessary. */ -void -xrealloc_and_strcat (str, lenp, src) - char **str; - size_t *lenp; - const char *src; -{ - - expand_string (str, lenp, strlen (*str) + strlen (src) + 1); - strcat (*str, src); -} - -/* - * Duplicate a string, calling xmalloc to allocate some dynamic space - */ -char * -xstrdup (str) - const char *str; -{ - char *s; - - if (str == NULL) - return ((char *) NULL); - s = xmalloc (strlen (str) + 1); - (void) strcpy (s, str); - return (s); -} - - - -/* Remove trailing newlines from STRING, destructively. - * - * RETURNS - * - * True if any newlines were removed, false otherwise. - */ -int -strip_trailing_newlines (str) - char *str; -{ - size_t index, origlen; - index = origlen = strlen (str); - - while (index > 0 && str[index-1] == '\n') - str[--index] = '\0'; - - return index != origlen; -} - - - -/* Return the number of levels that PATH ascends above where it starts. - * For example: - * - * "../../foo" -> 2 - * "foo/../../bar" -> 1 - */ -int -pathname_levels (p) - const char *p; -{ - int level; - int max_level; - - if (p == NULL) return 0; - - max_level = 0; - level = 0; - do - { - /* Now look for pathname level-ups. */ - if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || ISDIRSEP (p[2]))) - { - --level; - if (-level > max_level) - max_level = -level; - } - else if (p[0] == '\0' || ISDIRSEP (p[0]) || - (p[0] == '.' && (p[1] == '\0' || ISDIRSEP (p[1])))) - ; - else - ++level; - - /* q = strchr (p, '/'); but sub ISDIRSEP() for '/': */ - while (*p != '\0' && !ISDIRSEP (*p)) p++; - if (*p != '\0') p++; - } while (*p != '\0'); - return max_level; -} - - - -/* Free a vector, where (*ARGV)[0], (*ARGV)[1], ... (*ARGV)[*PARGC - 1] - are malloc'd and so is *ARGV itself. Such a vector is allocated by - line2argv or expand_wild, for example. */ -void -free_names (pargc, argv) - int *pargc; - char **argv; -{ - register int i; - - for (i = 0; i < *pargc; i++) - { /* only do through *pargc */ - free (argv[i]); - } - free (argv); - *pargc = 0; /* and set it to zero when done */ -} - -/* Convert LINE into arguments separated by SEPCHARS. Set *ARGC - to the number of arguments found, and (*ARGV)[0] to the first argument, - (*ARGV)[1] to the second, etc. *ARGV is malloc'd and so are each of - (*ARGV)[0], (*ARGV)[1], ... Use free_names() to return the memory - allocated here back to the free pool. */ -void -line2argv (pargc, argv, line, sepchars) - int *pargc; - char ***argv; - char *line; - char *sepchars; -{ - char *cp; - /* Could make a case for size_t or some other unsigned type, but - we'll stick with int to avoid signed/unsigned warnings when - comparing with *pargc. */ - int argv_allocated; - - /* Small for testing. */ - argv_allocated = 1; - *argv = (char **) xmalloc (argv_allocated * sizeof (**argv)); - - *pargc = 0; - for (cp = strtok (line, sepchars); cp; cp = strtok ((char *) NULL, sepchars)) - { - if (*pargc == argv_allocated) - { - argv_allocated *= 2; - *argv = xrealloc (*argv, argv_allocated * sizeof (**argv)); - } - (*argv)[*pargc] = xstrdup (cp); - (*pargc)++; - } -} - -/* - * Returns the number of dots ('.') found in an RCS revision number - */ -int -numdots (s) - const char *s; -{ - int dots = 0; - - for (; *s; s++) - { - if (*s == '.') - dots++; - } - return (dots); -} - -/* Compare revision numbers REV1 and REV2 by consecutive fields. - Return negative, zero, or positive in the manner of strcmp. The - two revision numbers must have the same number of fields, or else - compare_revnums will return an inaccurate result. */ -int -compare_revnums (rev1, rev2) - const char *rev1; - const char *rev2; -{ - const char *sp, *tp; - char *snext, *tnext; - int result = 0; - - sp = rev1; - tp = rev2; - while (result == 0) - { - result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10); - if (*snext == '\0' || *tnext == '\0') - break; - sp = snext + 1; - tp = tnext + 1; - } - - return result; -} - -/* Increment a revision number. Working on the string is a bit awkward, - but it avoid problems with integer overflow should the revision numbers - get really big. */ -char * -increment_revnum (rev) - const char *rev; -{ - char *newrev, *p; - size_t len = strlen (rev); - - newrev = xmalloc (len + 2); - memcpy (newrev, rev, len + 1); - for (p = newrev + len; p != newrev; ) - { - --p; - if (!isdigit(*p)) - { - ++p; - break; - } - if (*p != '9') - { - ++*p; - return newrev; - } - *p = '0'; - } - /* The number was all 9s, so change the first character to 1 and add - a 0 to the end. */ - *p = '1'; - p = newrev + len; - *p++ = '0'; - *p = '\0'; - return newrev; -} - -/* Return the username by which the caller should be identified in - CVS, in contexts such as the author field of RCS files, various - logs, etc. */ -char * -getcaller () -{ -#ifndef SYSTEM_GETCALLER - static char *cache; - struct passwd *pw; - uid_t uid; -#endif - - /* If there is a CVS username, return it. */ -#ifdef AUTH_SERVER_SUPPORT - if (CVS_Username != NULL) - return CVS_Username; -#endif - -#ifdef SYSTEM_GETCALLER - return SYSTEM_GETCALLER (); -#else - /* Get the caller's login from his uid. If the real uid is "root" - try LOGNAME USER or getlogin(). If getlogin() and getpwuid() - both fail, return the uid as a string. */ - - if (cache != NULL) - return cache; - - uid = getuid (); - if (uid == (uid_t) 0) - { - char *name; - - /* super-user; try getlogin() to distinguish */ - if (((name = getlogin ()) || (name = getenv("LOGNAME")) || - (name = getenv("USER"))) && *name) - { - cache = xstrdup (name); - return cache; - } - } - if ((pw = (struct passwd *) getpwuid (uid)) == NULL) - { - char uidname[20]; - - (void) sprintf (uidname, "uid%lu", (unsigned long) uid); - cache = xstrdup (uidname); - return cache; - } - cache = xstrdup (pw->pw_name); - return cache; -#endif -} - -#ifdef lint -#ifndef __GNUC__ -/* ARGSUSED */ -time_t -get_date (date, now) - char *date; - struct timeb *now; -{ - time_t foo = 0; - - return (foo); -} -#endif -#endif - - - -/* Given some revision, REV, return the first prior revision that exists in the - * RCS file, RCS. - * - * ASSUMPTIONS - * REV exists. - * - * INPUTS - * RCS The RCS node pointer. - * REV An existing revision in the RCS file referred to by RCS. - * - * RETURNS - * The first prior revision that exists in the RCS file, or NULL if no prior - * revision exists. The caller is responsible for disposing of this string. - * - * NOTES - * This function currently neglects the case where we are on the trunk with - * rev = X.1, where X != 1. If rev = X.Y, where X != 1 and Y > 1, then this - * function should work fine, as revision X.1 must exist, due to RCS rules. - */ -char * -previous_rev (rcs, rev) - RCSNode *rcs; - const char *rev; -{ - char *p; - char *tmp = xstrdup (rev); - long r1; - char *retval; - - /* Our retval can have no more digits and dots than our input revision. */ - retval = xmalloc (strlen (rev) + 1); - p = strrchr (tmp, '.'); - *p = '\0'; - r1 = strtol (p+1, NULL, 10); - do { - if (--r1 == 0) - { - /* If r1 == 0, then we must be on a branch and our parent must - * exist, or we must be on the trunk with a REV like X.1. - * We are neglecting the X.1 with X != 1 case by assuming that - * there is no previous revision when we discover we were on - * the trunk. - */ - p = strrchr (tmp, '.'); - if (p == NULL) - /* We are on the trunk. */ - retval = NULL; - else - { - *p = '\0'; - sprintf (retval, "%s", tmp); - } - break; - } - sprintf (retval, "%s.%ld", tmp, r1); - } while (!RCS_exist_rev (rcs, retval)); - - free (tmp); - return retval; -} - - - -/* Given two revisions, find their greatest common ancestor. If the - two input revisions exist, then rcs guarantees that the gca will - exist. */ - -char * -gca (rev1, rev2) - const char *rev1; - const char *rev2; -{ - int dots; - char *gca, *g; - const char *p1, *p2; - int r1, r2; - char *retval; - - if (rev1 == NULL || rev2 == NULL) - { - error (0, 0, "sanity failure in gca"); - abort(); - } - - /* The greatest common ancestor will have no more dots, and numbers - of digits for each component no greater than the arguments. Therefore - this string will be big enough. */ - g = gca = xmalloc (strlen (rev1) + strlen (rev2) + 100); - - /* walk the strings, reading the common parts. */ - p1 = rev1; - p2 = rev2; - do - { - r1 = strtol (p1, (char **) &p1, 10); - r2 = strtol (p2, (char **) &p2, 10); - - /* use the lowest. */ - (void) sprintf (g, "%d.", r1 < r2 ? r1 : r2); - g += strlen (g); - if (*p1 == '.') ++p1; - else break; - if (*p2 == '.') ++p2; - else break; - } while (r1 == r2); - - /* erase that last dot. */ - *--g = '\0'; - - /* numbers differ, or we ran out of strings. we're done with the - common parts. */ - - dots = numdots (gca); - if (dots == 0) - { - /* revisions differ in trunk major number. */ - - if (r2 < r1) p1 = p2; - if (*p1 == '\0') - { - /* we only got one number. this is strange. */ - error (0, 0, "bad revisions %s or %s", rev1, rev2); - abort(); - } - else - { - /* we have a minor number. use it. */ - *g++ = '.'; - while (*p1 != '.' && *p1 != '\0') - *g++ = *p1++; - *g = '\0'; - } - } - else if ((dots & 1) == 0) - { - /* if we have an even number of dots, then we have a branch. - remove the last number in order to make it a revision. */ - - g = strrchr (gca, '.'); - *g = '\0'; - } - - retval = xstrdup (gca); - free (gca); - return retval; -} - -/* Give fatal error if REV is numeric and ARGC,ARGV imply we are - planning to operate on more than one file. The current directory - should be the working directory. Note that callers assume that we - will only be checking the first character of REV; it need not have - '\0' at the end of the tag name and other niceties. Right now this - is only called from admin.c, but if people like the concept it probably - should also be called from diff -r, update -r, get -r, and log -r. */ - -void -check_numeric (rev, argc, argv) - const char *rev; - int argc; - char **argv; -{ - if (rev == NULL || !isdigit ((unsigned char) *rev)) - return; - - /* Note that the check for whether we are processing more than one - file is (basically) syntactic; that is, we don't behave differently - depending on whether a directory happens to contain only a single - file or whether it contains more than one. I strongly suspect this - is the least confusing behavior. */ - if (argc != 1 - || (!wrap_name_has (argv[0], WRAP_TOCVS) && isdir (argv[0]))) - { - error (0, 0, "while processing more than one file:"); - error (1, 0, "attempt to specify a numeric revision"); - } -} - -/* - * Sanity checks and any required fix-up on message passed to RCS via '-m'. - * RCS 5.7 requires that a non-total-whitespace, non-null message be provided - * with '-m'. Returns a newly allocated, non-empty buffer with whitespace - * stripped from end of lines and end of buffer. - * - * TODO: We no longer use RCS to manage repository files, so maybe this - * nonsense about non-empty log fields can be dropped. - */ -char * -make_message_rcslegal (message) - const char *message; -{ - char *dst, *dp; - const char *mp; - - if (message == NULL) message = ""; - - /* Strip whitespace from end of lines and end of string. */ - dp = dst = (char *) xmalloc (strlen (message) + 1); - for (mp = message; *mp != '\0'; ++mp) - { - if (*mp == '\n') - { - /* At end-of-line; backtrack to last non-space. */ - while (dp > dst && (dp[-1] == ' ' || dp[-1] == '\t')) - --dp; - } - *dp++ = *mp; - } - - /* Backtrack to last non-space at end of string, and truncate. */ - while (dp > dst && isspace ((unsigned char) dp[-1])) - --dp; - *dp = '\0'; - - /* After all that, if there was no non-space in the string, - substitute a non-empty message. */ - if (*dst == '\0') - { - free (dst); - dst = xstrdup ("*** empty log message ***"); - } - - return dst; -} - - - -/* Does the file FINFO contain conflict markers? The whole concept - of looking at the contents of the file to figure out whether there are - unresolved conflicts is kind of bogus (people do want to manage files - which contain those patterns not as conflict markers), but for now it - is what we do. */ -int -file_has_markers (finfo) - const struct file_info *finfo; -{ - FILE *fp; - char *line = NULL; - size_t line_allocated = 0; - int result; - - result = 0; - fp = CVS_FOPEN (finfo->file, "r"); - if (fp == NULL) - error (1, errno, "cannot open %s", finfo->fullname); - while (getline (&line, &line_allocated, fp) > 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; - } - } - if (ferror (fp)) - error (0, errno, "cannot read %s", finfo->fullname); -out: - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", finfo->fullname); - if (line != NULL) - free (line); - return result; -} - -/* Read the entire contents of the file NAME into *BUF. - If NAME is NULL, read from stdin. *BUF - is a pointer returned from malloc (or NULL), pointing to *BUFSIZE - bytes of space. The actual size is returned in *LEN. On error, - give a fatal error. The name of the file to use in error messages - (typically will include a directory if we have changed directory) - is FULLNAME. MODE is "r" for text or "rb" for binary. */ - -void -get_file (name, fullname, mode, buf, bufsize, len) - const char *name; - const char *fullname; - const char *mode; - char **buf; - size_t *bufsize; - size_t *len; -{ - struct stat s; - size_t nread; - char *tobuf; - FILE *e; - size_t filesize; - - if (name == NULL) - { - e = stdin; - filesize = 100; /* force allocation of minimum buffer */ - } - else - { - /* Although it would be cleaner in some ways to just read - until end of file, reallocating the buffer, this function - does get called on files in the working directory which can - be of arbitrary size, so I think we better do all that - extra allocation. */ - - if (CVS_STAT (name, &s) < 0) - error (1, errno, "can't stat %s", fullname); - - /* Convert from signed to unsigned. */ - filesize = s.st_size; - - e = open_file (name, mode); - } - - if (*buf == NULL || *bufsize <= filesize) - { - *bufsize = filesize + 1; - *buf = xrealloc (*buf, *bufsize); - } - - tobuf = *buf; - nread = 0; - while (1) - { - size_t got; - - got = fread (tobuf, 1, *bufsize - (tobuf - *buf), e); - if (ferror (e)) - error (1, errno, "can't read %s", fullname); - nread += got; - tobuf += got; - - if (feof (e)) - break; - - /* Allocate more space if needed. */ - if (tobuf == *buf + *bufsize) - { - int c; - long off; - - c = getc (e); - if (c == EOF) - break; - off = tobuf - *buf; - expand_string (buf, bufsize, *bufsize + 100); - tobuf = *buf + off; - *tobuf++ = c; - ++nread; - } - } - - if (e != stdin && fclose (e) < 0) - error (0, errno, "cannot close %s", fullname); - - *len = nread; - - /* Force *BUF to be large enough to hold a null terminator. */ - if (nread == *bufsize) - expand_string (buf, bufsize, *bufsize + 1); - (*buf)[nread] = '\0'; -} - - -/* Follow a chain of symbolic links to its destination. FILENAME - should be a handle to a malloc'd block of memory which contains the - beginning of the chain. This routine will replace the contents of - FILENAME with the destination (a real file). */ - -void -resolve_symlink (filename) - char **filename; -{ - if (filename == NULL || *filename == NULL) - return; - - while (islink (*filename)) - { -#ifdef HAVE_READLINK - /* The clean thing to do is probably to have each filesubr.c - implement this (with an error if not supported by the - platform, in which case islink would presumably return 0). - But that would require editing each filesubr.c and so the - expedient hack seems to be looking at HAVE_READLINK. */ - char *newname = xreadlink (*filename); - - if (isabsolute (newname)) - { - free (*filename); - *filename = newname; - } - else - { - const char *oldname = last_component (*filename); - int dirlen = oldname - *filename; - char *fullnewname = xmalloc (dirlen + strlen (newname) + 1); - strncpy (fullnewname, *filename, dirlen); - strcpy (fullnewname + dirlen, newname); - free (newname); - free (*filename); - *filename = fullnewname; - } -#else - error (1, 0, "internal error: islink doesn't like readlink"); -#endif - } -} - -/* - * Rename a file to an appropriate backup name based on BAKPREFIX. - * If suffix non-null, then ".<suffix>" 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; -} - -/* - * Copy a string into a buffer escaping any shell metacharacters. The - * buffer should be at least twice as long as the string. - * - * Returns a pointer to the terminating NUL byte in buffer. - */ - -char * -shell_escape(buf, str) - char *buf; - const char *str; -{ - static const char meta[] = "$`\\\""; - const char *p; - - for (;;) - { - p = strpbrk(str, meta); - if (!p) p = str + strlen(str); - if (p > str) - { - memcpy(buf, str, p - str); - buf += p - str; - } - if (!*p) break; - *buf++ = '\\'; - *buf++ = *p++; - str = p; - } - *buf = '\0'; - return buf; -} - - - -/* - * We can only travel forwards in time, not backwards. :) - */ -void -sleep_past (desttime) - time_t desttime; -{ - time_t t; - long s; - long us; - - while (time (&t) <= desttime) - { -#ifdef HAVE_GETTIMEOFDAY - struct timeval tv; - gettimeofday (&tv, NULL); - if (tv.tv_sec > desttime) - break; - s = desttime - tv.tv_sec; - if (tv.tv_usec > 0) - us = 1000000 - tv.tv_usec; - else - { - s++; - us = 0; - } -#else - /* default to 20 ms increments */ - s = desttime - t; - us = 20000; -#endif - -#if defined(HAVE_NANOSLEEP) - { - struct timespec ts; - ts.tv_sec = s; - ts.tv_nsec = us * 1000; - (void)nanosleep (&ts, NULL); - } -#elif defined(HAVE_USLEEP) - if (s > 0) - (void)sleep (s); - else - (void)usleep (us); -#elif defined(HAVE_SELECT) - { - /* use select instead of sleep since it is a fairly portable way of - * sleeping for ms. - */ - struct timeval tv; - tv.tv_sec = s; - tv.tv_usec = us; - (void)select (0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, - &tv); - } -#else - if (us > 0) s++; - (void)sleep(s); -#endif - } -} - - - -/* Return non-zero iff FILENAME is absolute. - Trivial under Unix, but more complicated under other systems. */ -int -isabsolute (filename) - const char *filename; -{ - return ISABSOLUTE (filename); -} diff --git a/contrib/cvs/src/tag.c b/contrib/cvs/src/tag.c deleted file mode 100644 index 43451ce..0000000 --- a/contrib/cvs/src/tag.c +++ /dev/null @@ -1,1465 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Tag and Rtag - * - * Add or delete a symbolic name to an RCS file, or a collection of RCS files. - * Tag uses the checked out revision in the current directory, rtag uses - * the modules database, if necessary. - * - * $FreeBSD$ - */ - -#include "cvs.h" -#include "savecwd.h" - -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 check_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static int check_filesdoneproc PROTO ((void *callerdat, int err, - const char *repos, - const char *update_dir, - List *entries)); -static int pretag_proc PROTO((const char *repository, const char *filter)); -static void masterlist_delproc PROTO((Node *p)); -static void tag_delproc PROTO((Node *p)); -static int pretag_list_proc PROTO((Node *p, void *closure)); - -static Dtype tag_dirproc PROTO ((void *callerdat, const char *dir, - const char *repos, const char *update_dir, - List *entries)); -static int rtag_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static int rtag_delete PROTO((RCSNode *rcsfile)); -static int tag_fileproc PROTO ((void *callerdat, struct file_info *finfo)); - -static char *numtag; /* specific revision to tag */ -static int numtag_validated = 0; -static char *date = NULL; -static char *symtag; /* tag to add or delete */ -static int delete_flag; /* adding a tag by default */ -static int branch_mode; /* make an automagic "branch" tag */ -static int disturb_branch_tags = 0; /* allow -F,-d to disturb branch tags */ -static int force_tag_match = 1; /* force tag to match by default */ -static int force_tag_move; /* don't force tag to move by default */ -static int check_uptodate; /* no uptodate-check by default */ -static int attic_too; /* remove tag from Attic files */ -static int is_rtag; - -struct tag_info -{ - Ctype status; - char *rev; - char *tag; - char *options; -}; - -struct master_lists -{ - List *tlist; -}; - -static List *mtlist; -static List *tlist; - -static const char rtag_opts[] = "+aBbdFflnQqRr:D:"; -static const char *const rtag_usage[] = -{ - "Usage: %s %s [-abdFflnR] [-r rev|-D date] tag modules...\n", - "\t-a\tClear tag from removed files that would not otherwise be tagged.\n", - "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n", - "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n", - "\t-d\tDelete the given tag.\n", - "\t-F\tMove tag if it already exists.\n", - "\t-f\tForce a head revision match if tag/date not found.\n", - "\t-l\tLocal directory only, not recursive.\n", - "\t-n\tNo execution of 'tag program'.\n", - "\t-R\tProcess directories recursively.\n", - "\t-r rev\tExisting revision/tag.\n", - "\t-D\tExisting date.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -static const char tag_opts[] = "+BbcdFflQqRr:D:"; -static const char *const tag_usage[] = -{ - "Usage: %s %s [-bcdFflR] [-r rev|-D date] tag [files...]\n", - "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n", - "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n", - "\t-c\tCheck that working files are unmodified.\n", - "\t-d\tDelete the given tag.\n", - "\t-F\tMove tag if it already exists.\n", - "\t-f\tForce a head revision match if tag/date not found.\n", - "\t-l\tLocal directory only, not recursive.\n", - "\t-R\tProcess directories recursively.\n", - "\t-r rev\tExisting revision/tag.\n", - "\t-D\tExisting date.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -int -cvstag (argc, argv) - int argc; - char **argv; -{ - int local = 0; /* recursive by default */ - int c; - int err = 0; - int run_module_prog = 1; - - is_rtag = (strcmp (cvs_cmd_name, "rtag") == 0); - - if (argc == -1) - usage (is_rtag ? rtag_usage : tag_usage); - - optind = 0; - while ((c = getopt (argc, argv, is_rtag ? rtag_opts : tag_opts)) != -1) - { - switch (c) - { - case 'a': - attic_too = 1; - break; - case 'b': - branch_mode = 1; - break; - case 'B': - disturb_branch_tags = 1; - break; - case 'c': - check_uptodate = 1; - break; - case 'd': - delete_flag = 1; - break; - case 'F': - force_tag_move = 1; - break; - case 'f': - force_tag_match = 0; - break; - case 'l': - local = 1; - break; - case 'n': - run_module_prog = 0; - break; - case 'Q': - case 'q': - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) - error (1, 0, - "-q or -Q must be specified before \"%s\"", - cvs_cmd_name); - break; - case 'R': - local = 0; - break; - case 'r': - numtag = optarg; - break; - case 'D': - if (date) - free (date); - date = Make_Date (optarg); - break; - case '?': - default: - usage (is_rtag ? rtag_usage : tag_usage); - break; - } - } - argc -= optind; - argv += optind; - - if (argc < (is_rtag ? 2 : 1)) - usage (is_rtag ? rtag_usage : tag_usage); - symtag = argv[0]; - argc--; - argv++; - - if (date && numtag) - error (1, 0, "-r and -D options are mutually exclusive"); - if (delete_flag && branch_mode) - error (0, 0, "warning: -b ignored with -d options"); - RCS_check_tag (symtag); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (attic_too) - send_arg("-a"); - if (branch_mode) - send_arg("-b"); - if (disturb_branch_tags) - send_arg("-B"); - if (check_uptodate) - send_arg("-c"); - if (delete_flag) - send_arg("-d"); - if (force_tag_move) - send_arg("-F"); - if (!force_tag_match) - send_arg ("-f"); - if (local) - send_arg("-l"); - if (!run_module_prog) - send_arg("-n"); - - if (numtag) - option_with_arg ("-r", numtag); - if (date) - client_senddate (date); - - send_arg ("--"); - - send_arg (symtag); - - if (is_rtag) - { - int i; - for (i = 0; i < argc; ++i) - send_arg (argv[i]); - send_to_server ("rtag\012", 0); - } - else - { - send_files (argc, argv, local, 0, - - /* I think the -c case is like "cvs status", in - which we really better be correct rather than - being fast; it is just too confusing otherwise. */ - check_uptodate ? 0 : SEND_NO_CONTENTS); - send_file_names (argc, argv, SEND_EXPAND_WILD); - send_to_server ("tag\012", 0); - } - - return get_responses_and_close (); - } -#endif - - if (is_rtag) - { - DBM *db; - int i; - db = open_module (); - for (i = 0; i < argc; i++) - { - /* XXX last arg should be repository, but doesn't make sense here */ - history_write ('T', (delete_flag ? "D" : (numtag ? numtag : - (date ? date : "A"))), symtag, argv[i], ""); - err += do_module (db, argv[i], TAG, - delete_flag ? "Untagging" : "Tagging", - rtag_proc, (char *) NULL, 0, local, run_module_prog, - 0, symtag); - } - close_module (db); - } - else - { - err = rtag_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, local, NULL, - NULL); - } - - return (err); -} - -/* - * callback proc for doing the real work of tagging - */ -/* ARGSUSED */ -static int -rtag_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified, - mname, msg) - int argc; - char **argv; - char *xwhere; - char *mwhere; - char *mfile; - int shorten; - int local_specified; - char *mname; - char *msg; -{ - /* Begin section which is identical to patch_proc--should this - be abstracted out somehow? */ - char *myargv[2]; - int err = 0; - int which; - char *repository; - char *where; - - if (is_rtag) - { - repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0]) - + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2); - (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); - where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1) - + 1); - (void) strcpy (where, argv[0]); - - /* if mfile isn't null, we need to set up to do only part of the module */ - if (mfile != NULL) - { - char *cp; - char *path; - - /* if the portion of the module is a path, put the dir part on repos */ - if ((cp = strrchr (mfile, '/')) != NULL) - { - *cp = '\0'; - (void) strcat (repository, "/"); - (void) strcat (repository, mfile); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - mfile = cp + 1; - } - - /* take care of the rest */ - path = xmalloc (strlen (repository) + strlen (mfile) + 5); - (void) sprintf (path, "%s/%s", repository, mfile); - if (isdir (path)) - { - /* directory means repository gets the dir tacked on */ - (void) strcpy (repository, path); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - } - else - { - myargv[0] = argv[0]; - myargv[1] = mfile; - argc = 2; - argv = myargv; - } - free (path); - } - - /* cd to the starting repository */ - if ( CVS_CHDIR (repository) < 0) - { - error (0, errno, "cannot chdir to %s", repository); - free (repository); - free (where); - return (1); - } - /* End section which is identical to patch_proc. */ - - if (delete_flag || force_tag_move || attic_too || numtag) - which = W_REPOS | W_ATTIC; - else - which = W_REPOS; - } - else - { - where = NULL; - which = W_LOCAL; - repository = ""; - } - - if (numtag != NULL && !numtag_validated) - { - tag_check_valid (numtag, argc - 1, argv + 1, local_specified, 0, repository); - numtag_validated = 1; - } - - /* check to make sure they are authorized to tag all the - specified files in the repository */ - - mtlist = getlist(); - err = start_recursion (check_fileproc, check_filesdoneproc, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc - 1, argv + 1, local_specified, which, 0, - CVS_LOCK_READ, where, 1, repository); - - if (err) - { - error (1, 0, "correct the above errors first!"); - } - - /* It would be nice to provide consistency with respect to - commits; however CVS lacks the infrastructure to do that (see - Concurrency in cvs.texinfo and comment in do_recursion). */ - - /* start the recursion processor */ - err = start_recursion (is_rtag ? rtag_fileproc : tag_fileproc, - (FILESDONEPROC) NULL, tag_dirproc, - (DIRLEAVEPROC) NULL, NULL, argc - 1, argv + 1, - local_specified, which, 0, CVS_LOCK_WRITE, where, 1, - repository); - if ( which & W_REPOS ) free ( repository ); - dellist (&mtlist); - if (where != NULL) - free (where); - return (err); -} - -/* check file that is to be tagged */ -/* All we do here is add it to our list */ - -static int -check_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - const char *xdir; - Node *p; - Vers_TS *vers; - - if (check_uptodate) - { - switch (Classify_File (finfo, (char *) NULL, (char *) NULL, - (char *) NULL, 1, 0, &vers, 0)) - { - case T_UPTODATE: - case T_CHECKOUT: - case T_PATCH: - case T_REMOVE_ENTRY: - break; - case T_UNKNOWN: - case T_CONFLICT: - case T_NEEDS_MERGE: - case T_MODIFIED: - case T_ADDED: - case T_REMOVED: - default: - 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 = "."; - else - xdir = finfo->update_dir; - if ((p = findnode (mtlist, xdir)) != NULL) - { - tlist = ((struct master_lists *) p->data)->tlist; - } - else - { - struct master_lists *ml; - - tlist = getlist (); - p = getnode (); - p->key = xstrdup (xdir); - p->type = UPDATE; - ml = (struct master_lists *) - xmalloc (sizeof (struct master_lists)); - ml->tlist = tlist; - p->data = ml; - p->delproc = masterlist_delproc; - (void) addnode (mtlist, p); - } - /* do tlist */ - p = getnode (); - p->key = xstrdup (finfo->file); - p->type = UPDATE; - p->delproc = tag_delproc; - if (vers->srcfile == NULL) - { - if (!really_quiet) - error (0, 0, "nothing known about %s", finfo->file); - freevers_ts (&vers); - freenode (p); - return (1); - } - - /* Here we duplicate the calculation in tag_fileproc about which - version we are going to tag. There probably are some subtle races - (e.g. numtag is "foo" which gets moved between here and - tag_fileproc). */ - if (!is_rtag && numtag == NULL && date == NULL) - p->data = xstrdup (vers->vn_user); - else - p->data = RCS_getversion (vers->srcfile, numtag, date, - force_tag_match, NULL); - - if (p->data != NULL) - { - int addit = 1; - char *oversion; - - oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, - (int *) NULL); - if (oversion == NULL) - { - if (delete_flag) - { - /* Deleting a tag which did not exist is a noop and - should not be logged. */ - addit = 0; - } - } - else if (delete_flag) - { - free (p->data); - p->data = xstrdup (oversion); - } - else if (strcmp(oversion, p->data) == 0) - { - addit = 0; - } - else if (!force_tag_move) - { - addit = 0; - } - if (oversion != NULL) - { - free(oversion); - } - if (!addit) - { - free(p->data); - p->data = NULL; - } - } - freevers_ts (&vers); - (void) addnode (tlist, p); - return (0); -} - -static int -check_filesdoneproc (callerdat, err, repos, update_dir, entries) - void *callerdat; - int err; - const char *repos; - const char *update_dir; - List *entries; -{ - int n; - Node *p; - - p = findnode(mtlist, update_dir); - if (p != NULL) - { - tlist = ((struct master_lists *) p->data)->tlist; - } - else - { - tlist = (List *) NULL; - } - if ((tlist == NULL) || (tlist->list->next == tlist->list)) - { - return (err); - } - if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0) - { - error (0, 0, "Pre-tag check failed"); - err += n; - } - return (err); -} - -static int -pretag_proc (repository, filter) - const char *repository; - const char *filter; -{ - if (filter[0] == '/') - { - char *s, *cp; - - s = xstrdup(filter); - for (cp=s; *cp; cp++) - { - if (isspace ((unsigned char) *cp)) - { - *cp = '\0'; - break; - } - } - if (!isfile(s)) - { - error (0, errno, "cannot find pre-tag filter '%s'", s); - free(s); - return (1); - } - free(s); - } - run_setup (filter); - run_arg (symtag); - run_arg (delete_flag ? "del" : force_tag_move ? "mov" : "add"); - run_arg (repository); - walklist(tlist, pretag_list_proc, NULL); - return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)); -} - -static void -masterlist_delproc(p) - Node *p; -{ - struct master_lists *ml = p->data; - - dellist(&ml->tlist); - free(ml); - return; -} - -static void -tag_delproc(p) - Node *p; -{ - if (p->data != NULL) - { - free(p->data); - p->data = NULL; - } - return; -} - -static int -pretag_list_proc(p, closure) - Node *p; - void *closure; -{ - if (p->data != NULL) - { - run_arg(p->key); - run_arg(p->data); - } - return (0); -} - - -/* - * Called to rtag a particular file, as appropriate with the options that were - * set above. - */ -/* ARGSUSED */ -static int -rtag_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - RCSNode *rcsfile; - char *version, *rev; - int retcode = 0; - - /* find the parsed RCS data */ - if ((rcsfile = finfo->rcs) == NULL) - return (1); - - /* - * For tagging an RCS file which is a symbolic link, you'd best be - * running with RCS 5.6, since it knows how to handle symbolic links - * correctly without breaking your link! - */ - - if (delete_flag) - return (rtag_delete (rcsfile)); - - /* - * If we get here, we are adding a tag. But, if -a was specified, we - * need to check to see if a -r or -D option was specified. If neither - * was specified and the file is in the Attic, remove the tag. - */ - if (attic_too && (!numtag && !date)) - { - if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC)) - return (rtag_delete (rcsfile)); - } - - version = RCS_getversion (rcsfile, numtag, date, force_tag_match, - (int *) NULL); - if (version == NULL) - { - /* If -a specified, clean up any old tags */ - if (attic_too) - (void) rtag_delete (rcsfile); - - if (!quiet && !force_tag_match) - { - error (0, 0, "cannot find tag `%s' in `%s'", - numtag ? numtag : "head", rcsfile->path); - return (1); - } - return (0); - } - if (numtag - && isdigit ((unsigned char) *numtag) - && strcmp (numtag, version) != 0) - { - - /* - * We didn't find a match for the numeric tag that was specified, but - * that's OK. just pass the numeric tag on to rcs, to be tagged as - * specified. Could get here if one tried to tag "1.1.1" and there - * was a 1.1.1 branch with some head revision. In this case, we want - * the tag to reference "1.1.1" and not the revision at the head of - * the branch. Use a symbolic tag for that. - */ - rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag; - retcode = RCS_settag(rcsfile, symtag, numtag); - if (retcode == 0) - RCS_rewrite (rcsfile, NULL, NULL); - } - else - { - char *oversion; - - /* - * As an enhancement for the case where a tag is being re-applied to - * a large body of a module, make one extra call to RCS_getversion to - * see if the tag is already set in the RCS file. If so, check to - * see if it needs to be moved. If not, do nothing. This will - * likely save a lot of time when simply moving the tag to the - * "current" head revisions of a module -- which I have found to be a - * typical tagging operation. - */ - rev = branch_mode ? RCS_magicrev (rcsfile, version) : version; - oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, - (int *) NULL); - if (oversion != NULL) - { - int isbranch = RCS_nodeisbranch (finfo->rcs, symtag); - - /* - * if versions the same and neither old or new are branches don't - * have to do anything - */ - if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch) - { - free (oversion); - free (version); - return (0); - } - - if (!force_tag_move) - { - /* we're NOT going to move the tag */ - (void) printf ("W %s", finfo->fullname); - - (void) printf (" : %s already exists on %s %s", - symtag, isbranch ? "branch" : "version", - oversion); - (void) printf (" : NOT MOVING tag to %s %s\n", - branch_mode ? "branch" : "version", rev); - free (oversion); - free (version); - if (branch_mode) free(rev); - return (0); - } - else /* force_tag_move is set and... */ - if ((isbranch && !disturb_branch_tags) || - (!isbranch && disturb_branch_tags)) - { - error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.", - finfo->fullname, - isbranch ? "branch" : "non-branch", - symtag, oversion, rev, - isbranch ? "" : " due to `-B' option"); - if (branch_mode) free(rev); - free (oversion); - free (version); - return (0); - } - free (oversion); - } - retcode = RCS_settag(rcsfile, symtag, rev); - if (retcode == 0) - RCS_rewrite (rcsfile, NULL, NULL); - } - - if (retcode != 0) - { - error (1, retcode == -1 ? errno : 0, - "failed to set tag `%s' to revision `%s' in `%s'", - symtag, rev, rcsfile->path); - if (branch_mode) - free (rev); - free (version); - return (1); - } - if (branch_mode) - free (rev); - free (version); - return (0); -} - -/* - * If -d is specified, "force_tag_match" is set, so that this call to - * RCS_getversion() will return a NULL version string if the symbolic - * tag does not exist in the RCS file. - * - * If the -r flag was used, numtag is set, and we only delete the - * symtag from files that have numtag. - * - * This is done here because it's MUCH faster than just blindly calling - * "rcs" to remove the tag... trust me. - */ -static int -rtag_delete (rcsfile) - RCSNode *rcsfile; -{ - char *version; - int retcode, isbranch; - - if (numtag) - { - version = RCS_getversion (rcsfile, numtag, (char *) NULL, 1, - (int *) NULL); - if (version == NULL) - return (0); - free (version); - } - - version = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, - (int *) NULL); - if (version == NULL) - return (0); - free (version); - - - isbranch = RCS_nodeisbranch (rcsfile, symtag); - if ((isbranch && !disturb_branch_tags) || - (!isbranch && disturb_branch_tags)) - { - if (!quiet) - error(0, 0, - "Not removing %s tag `%s' from `%s'%s.", - isbranch ? "branch" : "non-branch", - symtag, rcsfile->path, - isbranch ? "" : " due to `-B' option"); - return (1); - } - - if ((retcode = RCS_deltag(rcsfile, symtag)) != 0) - { - if (!quiet) - error (0, retcode == -1 ? errno : 0, - "failed to remove tag `%s' from `%s'", symtag, - rcsfile->path); - return (1); - } - RCS_rewrite (rcsfile, NULL, NULL); - return (0); -} - - -/* - * Called to tag a particular file (the currently checked out version is - * tagged with the specified tag - or the specified tag is deleted). - */ -/* ARGSUSED */ -static int -tag_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - char *version, *oversion; - char *nversion = NULL; - char *rev; - Vers_TS *vers; - int retcode = 0; - int retval = 0; - - vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0); - - if ((numtag != NULL) || (date != NULL)) - { - nversion = RCS_getversion(vers->srcfile, - numtag, - date, - force_tag_match, - (int *) NULL); - if (nversion == NULL) - goto free_vars_and_return; - } - if (delete_flag) - { - - int isbranch; - /* - * If -d is specified, "force_tag_match" is set, so that this call to - * RCS_getversion() will return a NULL version string if the symbolic - * tag does not exist in the RCS file. - * - * This is done here because it's MUCH faster than just blindly calling - * "rcs" to remove the tag... trust me. - */ - - version = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, - (int *) NULL); - if (version == NULL || vers->srcfile == NULL) - goto free_vars_and_return; - - free (version); - - isbranch = RCS_nodeisbranch (finfo->rcs, symtag); - if ((isbranch && !disturb_branch_tags) || - (!isbranch && disturb_branch_tags)) - { - if (!quiet) - error(0, 0, - "Not removing %s tag `%s' from `%s'%s.", - isbranch ? "branch" : "non-branch", - symtag, vers->srcfile->path, - isbranch ? "" : " due to `-B' option"); - retval = 1; - goto free_vars_and_return; - } - - if ((retcode = RCS_deltag(vers->srcfile, symtag)) != 0) - { - if (!quiet) - error (0, retcode == -1 ? errno : 0, - "failed to remove tag %s from %s", symtag, - vers->srcfile->path); - retval = 1; - goto free_vars_and_return; - } - RCS_rewrite (vers->srcfile, NULL, NULL); - - /* warm fuzzies */ - if (!really_quiet) - { - cvs_output ("D ", 2); - cvs_output (finfo->fullname, 0); - cvs_output ("\n", 1); - } - - goto free_vars_and_return; - } - - /* - * If we are adding a tag, we need to know which version we have checked - * out and we'll tag that version. - */ - if (nversion == NULL) - { - version = vers->vn_user; - } - else - { - version = nversion; - } - if (version == NULL) - { - goto free_vars_and_return; - } - else if (strcmp (version, "0") == 0) - { - if (!quiet) - error (0, 0, "couldn't tag added but un-commited file `%s'", finfo->file); - goto free_vars_and_return; - } - else if (version[0] == '-') - { - if (!quiet) - error (0, 0, "skipping removed but un-commited file `%s'", finfo->file); - goto free_vars_and_return; - } - else if (vers->srcfile == NULL) - { - if (!quiet) - error (0, 0, "cannot find revision control file for `%s'", finfo->file); - goto free_vars_and_return; - } - - /* - * As an enhancement for the case where a tag is being re-applied to a - * large number of files, make one extra call to RCS_getversion to see - * if the tag is already set in the RCS file. If so, check to see if it - * needs to be moved. If not, do nothing. This will likely save a lot of - * time when simply moving the tag to the "current" head revisions of a - * module -- which I have found to be a typical tagging operation. - */ - rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version; - oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, - (int *) NULL); - if (oversion != NULL) - { - int isbranch = RCS_nodeisbranch (finfo->rcs, symtag); - - /* - * if versions the same and neither old or new are branches don't have - * to do anything - */ - if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch) - { - free (oversion); - if (branch_mode) - free (rev); - goto free_vars_and_return; - } - - if (!force_tag_move) - { - /* we're NOT going to move the tag */ - cvs_output ("W ", 2); - cvs_output (finfo->fullname, 0); - cvs_output (" : ", 0); - cvs_output (symtag, 0); - cvs_output (" already exists on ", 0); - cvs_output (isbranch ? "branch" : "version", 0); - cvs_output (" ", 0); - cvs_output (oversion, 0); - cvs_output (" : NOT MOVING tag to ", 0); - cvs_output (branch_mode ? "branch" : "version", 0); - cvs_output (" ", 0); - cvs_output (rev, 0); - cvs_output ("\n", 1); - free (oversion); - if (branch_mode) - free (rev); - goto free_vars_and_return; - } - else /* force_tag_move == 1 and... */ - if ((isbranch && !disturb_branch_tags) || - (!isbranch && disturb_branch_tags)) - { - error(0,0, "%s: Not moving %s tag `%s' from %s to %s%s.", - finfo->fullname, - isbranch ? "branch" : "non-branch", - symtag, oversion, rev, - isbranch ? "" : " due to `-B' option"); - free (oversion); - if (branch_mode) - free (rev); - goto free_vars_and_return; - } - free (oversion); - } - - if ((retcode = RCS_settag(vers->srcfile, symtag, rev)) != 0) - { - 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); - retval = 1; - goto free_vars_and_return; - } - if (branch_mode) - free (rev); - RCS_rewrite (vers->srcfile, NULL, NULL); - - /* more warm fuzzies */ - if (!really_quiet) - { - cvs_output ("T ", 2); - cvs_output (finfo->fullname, 0); - cvs_output ("\n", 1); - } - - free_vars_and_return: - if (nversion != NULL) - free (nversion); - freevers_ts (&vers); - return (retval); -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -tag_dirproc (callerdat, dir, repos, update_dir, entries) - void *callerdat; - const char *dir; - const char *repos; - const char *update_dir; - List *entries; -{ - - if (ignore_directory (update_dir)) - { - /* print the warm fuzzy message */ - if (!quiet) - error (0, 0, "Ignoring %s", update_dir); - return R_SKIP_ALL; - } - - if (!quiet) - error (0, 0, "%s %s", delete_flag ? "Untagging" : "Tagging", update_dir); - return (R_PROCESS); -} - -/* Code relating to the val-tags file. Note that this file has no way - of knowing when a tag has been deleted. The problem is that there - is no way of knowing whether a tag still exists somewhere, when we - delete it some places. Using per-directory val-tags files (in - CVSREP) might be better, but that might slow down the process of - verifying that a tag is correct (maybe not, for the likely cases, - if carefully done), and/or be harder to implement correctly. */ - -struct val_args { - char *name; - int found; -}; - -static int val_fileproc PROTO ((void *callerdat, struct file_info *finfo)); - -static int -val_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - RCSNode *rcsdata; - struct val_args *args = (struct val_args *)callerdat; - char *tag; - - if ((rcsdata = finfo->rcs) == NULL) - /* Not sure this can happen, after all we passed only - W_REPOS | W_ATTIC. */ - return 0; - - tag = RCS_gettag (rcsdata, args->name, 1, (int *) NULL); - if (tag != NULL) - { - /* FIXME: should find out a way to stop the search at this point. */ - args->found = 1; - free (tag); - } - return 0; -} - - - -/* This routine determines whether a tag appears in CVSROOT/val-tags. - * - * The val-tags file will be open read-only when IDB is NULL. Since writes to - * val-tags always append to it, the lack of locking is okay. The worst case - * race condition might misinterpret a partially written "foobar" matched, for - * instance, a request for "f", "foo", of "foob". Such a mismatch would be - * caught harmlessly later. - * - * Before CVS adds a tag to val-tags, it will lock val-tags for write and - * verify that the tag is still not present to avoid adding it twice. - * - * NOTES - * This function expects its parent to handle any necessary locking of the - * val-tags file. - * - * INPUTS - * idb When this value is NULL, the val-tags file is opened in - * in read-only mode. When present, the val-tags file is opened - * in read-write mode and the DBM handle is stored in *IDB. - * name The tag to search for. - * - * OUTPUTS - * *idb The val-tags file opened for read/write, or NULL if it couldn't - * be opened. - * - * ERRORS - * Exits with an error message if the val-tags file cannot be opened for - * read (failure to open val-tags read/write is harmless - see below). - * - * RETURNS - * true 1. If NAME exists in val-tags. - * 2. If IDB is non-NULL and val-tags cannot be opened for write. - * This allows callers to ignore the harmless inability to - * update the val-tags cache. - * false If the file could be opened and the tag is not present. - */ -static int is_in_val_tags PROTO((DBM **idb, const char *name)); -static int -is_in_val_tags (idb, name) - DBM **idb; - const char *name; -{ - DBM *db = NULL; - char *valtags_filename; - datum mytag; - int status; - - /* Casting out const should be safe here - input datums are not - * written to by the myndbm functions. - */ - mytag.dptr = (char *)name; - mytag.dsize = strlen (name); - - valtags_filename = xmalloc (strlen (current_parsed_root->directory) - + sizeof CVSROOTADM - + sizeof CVSROOTADM_VALTAGS + 3); - sprintf (valtags_filename, "%s/%s/%s", current_parsed_root->directory, - CVSROOTADM, CVSROOTADM_VALTAGS); - - if (idb) - { - db = dbm_open (valtags_filename, O_RDWR, 0666); - if (!db) - { - mode_t omask; - - if (!existence_error (errno)) - { - error (0, errno, "warning: cannot open %s read/write", - valtags_filename); - *idb = NULL; - return 1; - } - - omask = umask (cvsumask); - db = dbm_open (valtags_filename, O_RDWR | O_CREAT | O_TRUNC, 0666); - umask (omask); - if (!db) - { - error (0, errno, "warning: cannot create %s", - valtags_filename); - *idb = NULL; - return 1; - } - - *idb = db; - return 0; - } - - *idb = db; - } - else - { - db = dbm_open (valtags_filename, O_RDONLY, 0444); - if (!db && !existence_error (errno)) - error (1, errno, "cannot read %s", valtags_filename); - } - - /* If the file merely fails to exist, we just keep going and create - it later if need be. */ - - status = 0; - if (db) - { - datum val; - - val = dbm_fetch (db, mytag); - if (val.dptr != NULL) - /* Found. The tag is valid. */ - status = 1; - - /* FIXME: should check errors somehow (add dbm_error to myndbm.c?). */ - - if (!idb) dbm_close (db); - } - - free (valtags_filename); - return status; -} - - - -/* Add a tag to the CVSROOT/val-tags cache. Establishes a write lock and - * reverifies that the tag does not exist before adding it. - */ -static void add_to_val_tags PROTO((const char *name)); -static void -add_to_val_tags (name) - const char *name; -{ - DBM *db; - datum mytag; - datum value; - - if (noexec) return; - - val_tags_lock (current_parsed_root->directory); - - /* Check for presence again since we have a lock now. */ - if (is_in_val_tags (&db, name)) - { - clear_val_tags_lock (); - if (db) - dbm_close (db); - return; - } - - /* Casting out const should be safe here - input datums are not - * written to by the myndbm functions. - */ - mytag.dptr = (char *)name; - mytag.dsize = strlen (name); - value.dptr = "y"; - value.dsize = 1; - - if (dbm_store (db, mytag, value, DBM_REPLACE) < 0) - error (0, errno, "failed to store %s into val-tags", name); - dbm_close (db); - - clear_val_tags_lock (); -} - - - -static Dtype val_direntproc PROTO ((void *, const char *, const char *, - const char *, List *)); - -static Dtype -val_direntproc (callerdat, dir, repository, update_dir, entries) - void *callerdat; - const char *dir; - const char *repository; - const char *update_dir; - List *entries; -{ - /* This is not quite right--it doesn't get right the case of "cvs - update -d -r foobar" where foobar is a tag which exists only in - files in a directory which does not exist yet, but which is - about to be created. */ - if (isdir (dir)) - return R_PROCESS; - return R_SKIP_ALL; -} - -/* Check to see whether NAME is a valid tag. If so, return. If not - print an error message and exit. ARGC, ARGV, LOCAL, and AFLAG specify - which files we will be operating on. - - REPOSITORY is the repository if we need to cd into it, or NULL if - we are already there, or "" if we should do a W_LOCAL recursion. - Sorry for three cases, but the "" case is needed in case the - working directories come from diverse parts of the repository, the - NULL case avoids an unneccesary chdir, and the non-NULL, non-"" - case is needed for checkout, where we don't want to chdir if the - tag is found in CVSROOTADM_VALTAGS, but there is not (yet) any - local directory. */ -void -tag_check_valid (name, argc, argv, local, aflag, repository) - char *name; - int argc; - char **argv; - int local; - int aflag; - char *repository; -{ - struct val_args the_val_args; - struct saved_cwd cwd; - int which; - - /* Numeric tags require only a syntactic check. */ - if (isdigit ((unsigned char) name[0])) - { - char *p; - for (p = name; *p != '\0'; ++p) - { - if (!(isdigit ((unsigned char) *p) || *p == '.')) - error (1, 0, "\ -Numeric tag %s contains characters other than digits and '.'", name); - } - return; - } - - /* Special tags are always valid. */ - if (strcmp (name, TAG_BASE) == 0 - || strcmp (name, TAG_HEAD) == 0) - return; - - if (readonlyfs) - return; - - /* Verify that the tag is valid syntactically. Some later code once made - * assumptions about this. - */ - RCS_check_tag (name); - - if (is_in_val_tags (NULL, name)) return; - - /* We didn't find the tag in val-tags, so look through all the RCS files - to see whether it exists there. Yes, this is expensive, but there - is no other way to cope with a tag which might have been created - by an old version of CVS, from before val-tags was invented. - - Since we need this code anyway, we also use it to create - entries in val-tags in general (that is, the val-tags entry - will get created the first time the tag is used, not when the - tag is created). */ - - the_val_args.name = name; - the_val_args.found = 0; - - which = W_REPOS | W_ATTIC; - - if (repository != NULL) - { - if (repository[0] == '\0') - which |= W_LOCAL; - else - { - if (save_cwd (&cwd)) - error_exit (); - if (CVS_CHDIR (repository) < 0) - error (1, errno, "cannot change to %s directory", repository); - } - } - - start_recursion (val_fileproc, (FILESDONEPROC) NULL, - val_direntproc, (DIRLEAVEPROC) NULL, - (void *)&the_val_args, - argc, argv, local, which, aflag, - CVS_LOCK_READ, NULL, 1, repository); - if (repository != NULL && repository[0] != '\0') - { - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - } - - if (!the_val_args.found) - error (1, 0, "no such tag %s", name); - else - /* The tags is valid but not mentioned in val-tags. Add it. */ - add_to_val_tags (name); -} - - - -/* - * Check whether a join tag is valid. This is just like - * tag_check_valid, but we must stop before the colon if there is one. - */ - -void -tag_check_valid_join (join_tag, argc, argv, local, aflag, repository) - char *join_tag; - int argc; - char **argv; - int local; - int aflag; - char *repository; -{ - char *c, *s; - - c = xstrdup (join_tag); - s = strchr (c, ':'); - if (s != NULL) - { - if (isdigit ((unsigned char) join_tag[0])) - error (1, 0, - "Numeric join tag %s may not contain a date specifier", - join_tag); - - *s = '\0'; - /* hmmm... I think it makes sense to allow -j:<date>, but - * for now this fixes a bug where CVS just spins and spins (I - * think in the RCS code) looking for a zero length tag. - */ - if (!*c) - error (1, 0, - "argument to join may not contain a date specifier without a tag"); - } - - tag_check_valid (c, argc, argv, local, aflag, repository); - - free (c); -} diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c deleted file mode 100644 index f2c8087..0000000 --- a/contrib/cvs/src/update.c +++ /dev/null @@ -1,3049 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * "update" updates the version in the present directory with respect to the RCS - * repository. The present version must have been created by "checkout". The - * user can keep up-to-date by calling "update" whenever he feels like it. - * - * The present version can be committed by "commit", but this keeps the version - * in tact. - * - * Arguments following the options are taken to be file names to be updated, - * rather than updating the entire directory. - * - * Modified or non-existent RCS files are checked out and reported as U - * <user_file> - * - * Modified user files are reported as M <user_file>. If both the RCS file and - * the user file have been modified, the user file is replaced by the result - * of rcsmerge, and a backup file is written for the user in .#file.version. - * If this throws up irreconcilable differences, the file is reported as C - * <user_file>, and as M <user_file> otherwise. - * - * Files added but not yet committed are reported as A <user_file>. Files - * removed but not yet committed are reported as R <user_file>. - * - * If the current directory contains subdirectories that hold concurrent - * versions, these are updated too. If the -d option was specified, new - * directories added to the repository are automatically created and updated - * as well. - * - * $FreeBSD$ - */ - -#include "cvs.h" -#include <assert.h> -#include "savecwd.h" -#ifdef SERVER_SUPPORT -# include "md5.h" -#endif -#include "watch.h" -#include "fileattr.h" -#include "edit.h" -#include "getline.h" -#include "buffer.h" -#include "hardlink.h" - -static int checkout_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts, - int adding, int merging, int update_server)); -#ifdef SERVER_SUPPORT -static void checkout_to_buffer PROTO ((void *, const char *, size_t)); -static int patch_file PROTO ((struct file_info *finfo, - Vers_TS *vers_ts, - int *docheckout, struct stat *file_info, - unsigned char *checksum)); -static void patch_file_write PROTO ((void *, const char *, size_t)); -#endif /* SERVER_SUPPORT */ -static int merge_file PROTO ((struct file_info *finfo, Vers_TS *vers)); -static int scratch_file PROTO((struct file_info *finfo, Vers_TS *vers)); -static Dtype update_dirent_proc PROTO ((void *callerdat, const char *dir, - const char *repository, - const char *update_dir, - List *entries)); -static int update_dirleave_proc PROTO ((void *callerdat, const char *dir, - int err, const char *update_dir, - List *entries)); -static int update_fileproc PROTO ((void *callerdat, struct file_info *)); -static int update_filesdone_proc PROTO ((void *callerdat, int err, - const char *repository, - const char *update_dir, - List *entries)); -#ifdef PRESERVE_PERMISSIONS_SUPPORT -static int get_linkinfo_proc PROTO ((void *callerdat, struct file_info *)); -#endif -static void join_file PROTO ((struct file_info *finfo, Vers_TS *vers_ts)); - -static char *options = NULL; -static char *tag = NULL; -static char *date = NULL; -/* This is a bit of a kludge. We call WriteTag at the beginning - before we know whether nonbranch is set or not. And then at the - end, once we have the right value for nonbranch, we call WriteTag - again. I don't know whether the first call is necessary or not. - rewrite_tag is nonzero if we are going to have to make that second - call. */ -static int rewrite_tag; -static int nonbranch; - -/* If we set the tag or date for a subdirectory, we use this to undo - the setting. See update_dirent_proc. */ -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 pull_template = 0; -static int update_build_dirs = 0; -static int update_prune_dirs = 0; -static int pipeout = 0; -#ifdef SERVER_SUPPORT -static int patches = 0; -static int rcs_diff_patches = 0; -#endif -static List *ignlist = (List *) NULL; -static time_t last_register_time; -static const char *const update_usage[] = -{ - "Usage: %s %s [-APCdflRp] [-k kopt] [-r rev] [-D date] [-j rev]\n", - " [-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", - "\t-R\tProcess directories recursively.\n", - "\t-p\tSend updates to standard output (avoids stickiness).\n", - "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n", - "\t-r rev\tUpdate using specified revision/tag (is sticky).\n", - "\t-D date\tSet date to update from (is sticky).\n", - "\t-j rev\tMerge in changes made between current revision and rev.\n", - "\t-I ign\tMore files to ignore (! to reset).\n", - "\t-W spec\tWrappers specification line.\n", - "\t-T\tCreate CVS/Template.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -/* - * update is the argv,argc based front end for arg parsing - */ -int -update (argc, argv) - int argc; - char **argv; -{ - int c, err; - int local = 0; /* recursive by default */ - int which; /* where to look for files and dirs */ - int xpull_template = 0; - - if (argc == -1) - usage (update_usage); - - ign_setup (); - wrap_setup (); - - /* parse the args */ - optind = 0; - while ((c = getopt (argc, argv, "+ApCPflRQTqduk: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; - case 'W': - wrap_add (optarg, 0); - break; - case 'k': - if (options) - free (options); - options = RCS_check_kflag (optarg); - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'Q': - case 'q': - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) - error (1, 0, - "-q or -Q must be specified before \"%s\"", - cvs_cmd_name); - break; - case 'T': - xpull_template = 1; - break; - case 'd': - update_build_dirs = 1; - break; - case 'f': - force_tag_match = 0; - break; - case 'r': - tag = optarg; - break; - case 'D': - if (date) free (date); - date = Make_Date (optarg); - break; - case 'P': - update_prune_dirs = 1; - break; - case 'p': - pipeout = 1; - noexec = 1; /* so no locks will be created */ - break; - case 'j': - if (join_rev2) - error (1, 0, "only two -j options can be specified"); - if (join_rev1) - join_rev2 = optarg; - else - join_rev1 = optarg; - break; - case 'u': -#ifdef SERVER_SUPPORT - if (server_active) - { - patches = 1; - rcs_diff_patches = server_use_rcs_diff (); - } - else -#endif - usage (update_usage); - break; - case '?': - default: - usage (update_usage); - break; - } - } - argc -= optind; - argv += optind; - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - int pass; - - /* The first pass does the regular update. If we receive at least - one patch which failed, we do a second pass and just fetch - those files whose patches failed. */ - pass = 1; - do - { - int status; - - start_server (); - - if (local) - send_arg("-l"); - if (update_build_dirs) - send_arg("-d"); - if (pipeout) - send_arg("-p"); - if (!force_tag_match) - 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; - option_with_arg ("-r", tag); - if (options && options[0] != '\0') - send_arg (options); - if (date) - client_senddate (date); - if (join_rev1) - option_with_arg ("-j", join_rev1); - if (join_rev2) - option_with_arg ("-j", join_rev2); - wrap_send (); - - 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"); - - send_arg ("--"); - - 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, flags); - send_file_names (argc, argv, SEND_EXPAND_WILD); - } - else - { - int i; - - (void) printf ("%s client: refetching unpatchable files\n", - program_name); - - if (toplevel_wd != NULL - && CVS_CHDIR (toplevel_wd) < 0) - { - error (1, errno, "could not chdir to %s", toplevel_wd); - } - - send_arg ("--"); - - for (i = 0; i < failed_patches_count; i++) - if (unlink_file (failed_patches[i]) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", - failed_patches[i]); - 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); - } - - send_to_server ("update\012", 0); - - status = get_responses_and_close (); - - /* If there are any conflicts, the server will return a - non-zero exit status. If any patches failed, we still - want to run the update again. We use a pass count to - avoid an endless loop. */ - - /* Notes: (1) assuming that status != 0 implies a - potential conflict is the best we can cleanly do given - the current protocol. I suppose that trying to - re-fetch in cases where there was a more serious error - is probably more or less harmless, but it isn't really - ideal. (2) it would be nice to have a testsuite case for the - conflict-and-patch-failed case. */ - - if (status != 0 - && (failed_patches_count == 0 || pass > 1)) - { - if (failed_patches_count > 0) - free_names (&failed_patches_count, failed_patches); - return status; - } - - ++pass; - } while (failed_patches_count > 0); - - return 0; - } -#endif - - if (tag != NULL) - tag_check_valid (tag, argc, argv, local, aflag, ""); - if (join_rev1 != NULL) - tag_check_valid_join (join_rev1, argc, argv, local, aflag, ""); - if (join_rev2 != NULL) - tag_check_valid_join (join_rev2, argc, argv, local, aflag, ""); - - /* - * If we are updating the entire directory (for real) and building dirs - * as we go, we make sure there is no static entries file and write the - * tag file as appropriate - */ - if (argc <= 0 && !pipeout) - { - if (update_build_dirs) - { - if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno)) - error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); -#ifdef SERVER_SUPPORT - if (server_active) - { - 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) - { - char *repos = Name_Repository (NULL, NULL); - WriteTag ((char *) NULL, tag, date, 0, ".", repos); - free (repos); - rewrite_tag = 1; - nonbranch = 0; - } - } - - /* look for files/dirs locally and in the repository */ - which = W_LOCAL | W_REPOS; - - /* look in the attic too if a tag or date is specified */ - if (tag != NULL || date != NULL || joining()) - which |= W_ATTIC; - - /* call the command line interface */ - err = do_update (argc, argv, options, tag, date, force_tag_match, - local, update_build_dirs, aflag, update_prune_dirs, - pipeout, which, join_rev1, join_rev2, (char *) NULL, - xpull_template, (char *) NULL); - - /* free the space Make_Date allocated if necessary */ - if (date != NULL) - free (date); - - return err; -} - - - -/* - * Command line interface to update (used by checkout) - */ -int -do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, - xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir, - xpull_template, repository) - int argc; - char **argv; - char *xoptions; - char *xtag; - char *xdate; - int xforce; - int local; - int xbuild; - int xaflag; - int xprune; - int xpipeout; - int which; - char *xjoin_rev1; - char *xjoin_rev2; - char *preload_update_dir; - int xpull_template; - char *repository; -{ - int err = 0; - char *cp; - - /* fill in the statics */ - options = xoptions; - tag = xtag; - date = xdate; - force_tag_match = xforce; - update_build_dirs = xbuild; - aflag = xaflag; - update_prune_dirs = xprune; - pipeout = xpipeout; - pull_template = xpull_template; - - /* setup the join support */ - join_rev1 = xjoin_rev1; - join_rev2 = xjoin_rev2; - if (join_rev1 && (cp = strchr (join_rev1, ':')) != NULL) - { - *cp++ = '\0'; - date_rev1 = Make_Date (cp); - } - else - date_rev1 = (char *) NULL; - if (join_rev2 && (cp = strchr (join_rev2, ':')) != NULL) - { - *cp++ = '\0'; - date_rev2 = Make_Date (cp); - } - else - date_rev2 = (char *) NULL; - -#ifdef PRESERVE_PERMISSIONS_SUPPORT - if (preserve_perms) - { - /* We need to do an extra recursion, bleah. It's to make sure - that we know as much as possible about file linkage. */ - hardlist = getlist(); - working_dir = xgetwd(); /* save top-level working dir */ - - /* FIXME-twp: the arguments to start_recursion make me dizzy. This - function call was copied from the update_fileproc call that - follows it; someone should make sure that I did it right. */ - err = start_recursion (get_linkinfo_proc, (FILESDONEPROC) NULL, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc, argv, local, which, aflag, CVS_LOCK_READ, - preload_update_dir, 1, (char *) NULL); - if (err) - return err; - - /* FIXME-twp: at this point we should walk the hardlist - and update the `links' field of each hardlink_info struct - to list the files that are linked on dist. That would make - it easier & more efficient to compare the disk linkage with - the repository linkage (a simple strcmp). */ - } -#endif - - /* call the recursion processor */ - err = start_recursion (update_fileproc, update_filesdone_proc, - update_dirent_proc, update_dirleave_proc, NULL, - argc, argv, local, which, aflag, CVS_LOCK_READ, - preload_update_dir, 1, repository); - - /* see if we need to sleep before returning to avoid time-stamp races */ - if (!server_active && last_register_time) - { - sleep_past (last_register_time); - } - - return err; -} - -#ifdef PRESERVE_PERMISSIONS_SUPPORT -/* - * The get_linkinfo_proc callback adds each file to the hardlist - * (see hardlink.c). - */ - -static int -get_linkinfo_proc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - char *fullpath; - Node *linkp; - struct hardlink_info *hlinfo; - - /* Get the full pathname of the current file. */ - fullpath = xmalloc (strlen(working_dir) + - strlen(finfo->fullname) + 2); - sprintf (fullpath, "%s/%s", working_dir, finfo->fullname); - - /* To permit recursing into subdirectories, files - are keyed on the full pathname and not on the basename. */ - linkp = lookup_file_by_inode (fullpath); - if (linkp == NULL) - { - /* The file isn't on disk; we are probably restoring - a file that was removed. */ - return 0; - } - - /* Create a new, empty hardlink_info node. */ - hlinfo = (struct hardlink_info *) - xmalloc (sizeof (struct hardlink_info)); - - hlinfo->status = (Ctype) 0; /* is this dumb? */ - hlinfo->checked_out = 0; - - linkp->data = hlinfo; - - return 0; -} -#endif - - - -/* - * This is the callback proc for update. It is called for each file in each - * directory by the recursion code. The current directory is the local - * instantiation. file is the file name we are to operate on. update_dir is - * set to the path relative to where we started (for pretty printing). - * repository is the repository. entries and srcfiles are the pre-parsed - * entries and source control files. - * - * This routine decides what needs to be done for each file and does the - * appropriate magic for checkout - */ -static int -update_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - int retval; - Ctype status; - Vers_TS *vers; - - status = Classify_File (finfo, tag, date, options, force_tag_match, - aflag, &vers, pipeout); - - /* Keep track of whether TAG is a branch tag. - Note that if it is a branch tag in some files and a nonbranch tag - in others, treat it as a nonbranch tag. It is possible that case - should elicit a warning or an error. */ - if (rewrite_tag - && tag != NULL - && finfo->rcs != NULL) - { - char *rev = RCS_getversion (finfo->rcs, tag, date, 1, NULL); - if (rev != NULL - && !RCS_nodeisbranch (finfo->rcs, tag)) - nonbranch = 1; - if (rev != NULL) - free (rev); - } - - if (pipeout) - { - /* - * We just return success without doing anything if any of the really - * funky cases occur - * - * If there is still a valid RCS file, do a regular checkout type - * operation - */ - switch (status) - { - case T_UNKNOWN: /* unknown file was explicitly asked - * about */ - case T_REMOVE_ENTRY: /* needs to be un-registered */ - case T_ADDED: /* added but not committed */ - retval = 0; - break; - case T_CONFLICT: /* old punt-type errors */ - retval = 1; - break; - case T_UPTODATE: /* file was already up-to-date */ - case T_NEEDS_MERGE: /* needs merging */ - case T_MODIFIED: /* locally modified */ - case T_REMOVED: /* removed but not committed */ - case T_CHECKOUT: /* needs checkout */ - case T_PATCH: /* needs patch */ - retval = checkout_file (finfo, vers, 0, 0, 0); - break; - - default: /* can't ever happen :-) */ - error (0, 0, - "unknown file status %d for file %s", status, finfo->file); - retval = 0; - break; - } - } - else - { - switch (status) - { - case T_UNKNOWN: /* unknown file was explicitly asked - * about */ - case T_UPTODATE: /* file was already up-to-date */ - retval = 0; - break; - case T_CONFLICT: /* old punt-type errors */ - retval = 1; - write_letter (finfo, 'C'); - break; - case T_NEEDS_MERGE: /* needs merging */ - if (! toss_local_changes) - { - retval = merge_file (finfo, vers); - break; - } - /* else FALL THROUGH */ - case T_MODIFIED: /* locally modified */ - retval = 0; - if (toss_local_changes) - { - char *bakname; - bakname = backup_file (finfo->file, vers->vn_user); - /* This behavior is sufficiently unexpected to - justify overinformativeness, I think. */ - if (!really_quiet && !server_active) - (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) - { - if (file_has_markers (finfo)) - { - 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'); - } - break; - case T_PATCH: /* needs patch */ -#ifdef SERVER_SUPPORT - if (patches) - { - int docheckout; - struct stat file_info; - unsigned char checksum[16]; - - retval = patch_file (finfo, - vers, &docheckout, - &file_info, checksum); - if (! docheckout) - { - if (server_active && retval == 0) - server_updated (finfo, vers, - (rcs_diff_patches - ? SERVER_RCS_DIFF - : SERVER_PATCHED), - file_info.st_mode, checksum, - (struct buffer *) NULL); - break; - } - } -#endif - /* If we're not running as a server, just check the - file out. It's simpler and faster than producing - and applying patches. */ - /* Fall through. */ - case T_CHECKOUT: /* needs checkout */ - retval = checkout_file (finfo, vers, 0, 0, 1); - break; - case T_ADDED: /* added but not committed */ - write_letter (finfo, 'A'); - retval = 0; - break; - case T_REMOVED: /* removed but not committed */ - write_letter (finfo, 'R'); - retval = 0; - break; - case T_REMOVE_ENTRY: /* needs to be un-registered */ - retval = scratch_file (finfo, vers); - break; - default: /* can't ever happen :-) */ - error (0, 0, - "unknown file status %d for file %s", status, finfo->file); - retval = 0; - break; - } - } - - /* only try to join if things have gone well thus far */ - if (retval == 0 && join_rev1) - join_file (finfo, vers); - - /* if this directory has an ignore list, add this file to it */ - if (ignlist && (status != T_UNKNOWN || vers->ts_user == NULL)) - { - Node *p; - - p = getnode (); - p->type = FILES; - p->key = xstrdup (finfo->file); - if (addnode (ignlist, p) != 0) - freenode (p); - } - - freevers_ts (&vers); - return retval; -} - - - -static void update_ignproc PROTO ((const char *, const char *)); - -static void -update_ignproc (file, dir) - const char *file; - const char *dir; -{ - struct file_info finfo; - char *tmp; - - memset (&finfo, 0, sizeof (finfo)); - finfo.file = file; - finfo.update_dir = dir; - if (dir[0] == '\0') - tmp = xstrdup (file); - else - { - tmp = xmalloc (strlen (file) + strlen (dir) + 10); - strcpy (tmp, dir); - strcat (tmp, "/"); - strcat (tmp, file); - } - - finfo.fullname = tmp; - write_letter (&finfo, '?'); - free (tmp); -} - - - -/* ARGSUSED */ -static int -update_filesdone_proc (callerdat, err, repository, update_dir, entries) - void *callerdat; - int err; - const char *repository; - const char *update_dir; - List *entries; -{ - if (rewrite_tag) - { - WriteTag (NULL, tag, date, nonbranch, update_dir, repository); - rewrite_tag = 0; - } - - /* if this directory has an ignore list, process it then free it */ - if (ignlist) - { - ignore_files (ignlist, entries, update_dir, update_ignproc); - dellist (&ignlist); - } - - /* Clean up CVS admin dirs if we are export */ - if (strcmp (cvs_cmd_name, "export") == 0) - { - /* I'm not sure the existence_error is actually possible (except - in cases where we really should print a message), but since - this code used to ignore all errors, I'll play it safe. */ - if (unlink_file_dir (CVSADM) < 0 && !existence_error (errno)) - error (0, errno, "cannot remove %s directory", CVSADM); - } - else if (!server_active && !pipeout) - { - /* If there is no CVS/Root file, add one */ - if (!isfile (CVSADM_ROOT)) - Create_Root ((char *) NULL, current_parsed_root->original); - } - - return err; -} - - - -/* - * update_dirent_proc () is called back by the recursion processor before a - * sub-directory is processed for update. In this case, update_dirent proc - * will probably create the directory unless -d isn't specified and this is a - * new directory. A return code of 0 indicates the directory should be - * processed by the recursion code. A return of non-zero indicates the - * recursion code should skip this directory. - */ -static Dtype -update_dirent_proc (callerdat, dir, repository, update_dir, entries) - void *callerdat; - const char *dir; - const char *repository; - const char *update_dir; - List *entries; -{ - if (ignore_directory (update_dir)) - { - /* print the warm fuzzy message */ - if (!quiet) - error (0, 0, "Ignoring %s", update_dir); - return R_SKIP_ALL; - } - - if (!isdir (dir)) - { - /* if we aren't building dirs, blow it off */ - if (!update_build_dirs) - return R_SKIP_ALL; - - /* Various CVS administrators are in the habit of removing - the repository directory for things they don't want any - more. I've even been known to do it myself (on rare - occasions). Not the usual recommended practice, but we - want to try to come up with some kind of - reasonable/documented/sensible behavior. Generally - the behavior is to just skip over that directory (see - dirs test in sanity.sh; the case which reaches here - is when update -d is specified, and the working directory - is gone but the subdirectory is still mentioned in - CVS/Entries). */ - /* In the remote case, the client should refrain from - sending us the directory in the first place. So we - want to continue to give an error, so clients make - sure to do this. */ - if (!server_active && !isdir (repository)) - return R_SKIP_ALL; - - if (noexec) - { - /* ignore the missing dir if -n is specified */ - error (0, 0, "New directory `%s' -- ignored", update_dir); - return R_SKIP_ALL; - } - else - { - /* otherwise, create the dir and appropriate adm files */ - - /* If no tag or date were specified on the command line, - and we're not using -A, we want the subdirectory to use - the tag and date, if any, of the current directory. - That way, update -d will work correctly when working on - a branch. - - We use TAG_UPDATE_DIR to undo the tag setting in - update_dirleave_proc. If we did not do this, we would - not correctly handle a working directory with multiple - tags (and maybe we should prohibit such working - directories, but they work now and we shouldn't make - them stop working without more thought). */ - if ((tag == NULL && date == NULL) && ! aflag) - { - ParseTag (&tag, &date, &nonbranch); - if (tag != NULL || date != NULL) - tag_update_dir = xstrdup (update_dir); - } - - make_directory (dir); - Create_Admin (dir, update_dir, repository, tag, date, - /* This is a guess. We will rewrite it later - via WriteTag. */ - 0, - 0, - pull_template); - rewrite_tag = 1; - nonbranch = 0; - Subdir_Register (entries, (char *) NULL, dir); - } - } - /* Do we need to check noexec here? */ - else if (!pipeout) - { - char *cvsadmdir; - - /* The directory exists. Check to see if it has a CVS - subdirectory. */ - - cvsadmdir = xmalloc (strlen (dir) + 80); - strcpy (cvsadmdir, dir); - strcat (cvsadmdir, "/"); - strcat (cvsadmdir, CVSADM); - - if (!isdir (cvsadmdir)) - { - /* We cannot successfully recurse into a directory without a CVS - subdirectory. Generally we will have already printed - "? foo". */ - free (cvsadmdir); - return R_SKIP_ALL; - } - free (cvsadmdir); - } - - /* - * If we are building dirs and not going to stdout, we make sure there is - * no static entries file and write the tag file as appropriate - */ - if (!pipeout) - { - if (update_build_dirs) - { - char *tmp; - - tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ENTSTAT) + 10); - (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT); - if (unlink_file (tmp) < 0 && ! existence_error (errno)) - error (1, errno, "cannot remove file %s", tmp); -#ifdef SERVER_SUPPORT - if (server_active) - server_clear_entstat (update_dir, repository); -#endif - free (tmp); - } - - /* keep the CVS/Tag file current with the specified arguments */ - if (aflag || tag || date) - { - WriteTag (dir, tag, date, 0, update_dir, repository); - rewrite_tag = 1; - nonbranch = 0; - } - - /* keep the CVS/Template file current */ - if (pull_template) - { - WriteTemplate (dir, update_dir); - } - - /* initialize the ignore list for this directory */ - ignlist = getlist (); - } - - /* print the warm fuzzy message */ - if (!quiet) - error (0, 0, "Updating %s", update_dir); - - return R_PROCESS; -} - - - -/* - * update_dirleave_proc () is called back by the recursion code upon leaving - * a directory. It will prune empty directories if needed and will execute - * any appropriate update programs. - */ -/* ARGSUSED */ -static int -update_dirleave_proc (callerdat, dir, err, update_dir, entries) - void *callerdat; - const char *dir; - int err; - const char *update_dir; - List *entries; -{ - /* 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 - date were both originally NULL in this case. */ - if (tag_update_dir != NULL && strcmp (update_dir, tag_update_dir) == 0) - { - if (tag != NULL) - { - free (tag); - tag = NULL; - } - if (date != NULL) - { - free (date); - date = NULL; - } - nonbranch = 0; - free (tag_update_dir); - tag_update_dir = NULL; - } - - if (strchr (dir, '/') == NULL) - { - /* FIXME: chdir ("..") loses with symlinks. */ - /* Prune empty dirs on the way out - if necessary */ - (void) CVS_CHDIR (".."); - if (update_prune_dirs && isemptydir (dir, 0)) - { - /* I'm not sure the existence_error is actually possible (except - in cases where we really should print a message), but since - this code used to ignore all errors, I'll play it safe. */ - if (unlink_file_dir (dir) < 0 && !existence_error (errno)) - error (0, errno, "cannot remove %s directory", dir); - Subdir_Deregister (entries, (char *) NULL, dir); - } - } - - return err; -} - - - -static int isremoved PROTO ((Node *, void *)); - -/* Returns 1 if the file indicated by node has been removed. */ -static int -isremoved (node, closure) - Node *node; - void *closure; -{ - Entnode *entdata = node->data; - - /* If the first character of the version is a '-', the file has been - removed. */ - return (entdata->version && entdata->version[0] == '-') ? 1 : 0; -} - - - -/* Returns 1 if the argument directory is completely empty, other than the - existence of the CVS directory entry. Zero otherwise. If MIGHT_NOT_EXIST - and the directory doesn't exist, then just return 0. */ -int -isemptydir (dir, might_not_exist) - const char *dir; - int might_not_exist; -{ - DIR *dirp; - struct dirent *dp; - - if ((dirp = CVS_OPENDIR (dir)) == NULL) - { - if (might_not_exist && existence_error (errno)) - return 0; - error (0, errno, "cannot open directory %s for empty check", dir); - return 0; - } - errno = 0; - while ((dp = CVS_READDIR (dirp)) != NULL) - { - if (strcmp (dp->d_name, ".") != 0 - && strcmp (dp->d_name, "..") != 0) - { - if (strcmp (dp->d_name, CVSADM) != 0) - { - /* An entry other than the CVS directory. The directory - is certainly not empty. */ - (void) CVS_CLOSEDIR (dirp); - return 0; - } - else - { - /* The CVS directory entry. We don't have to worry about - this unless the Entries file indicates that files have - been removed, but not committed, in this directory. - (Removing the directory would prevent people from - comitting the fact that they removed the files!) */ - List *l; - int files_removed; - struct saved_cwd cwd; - - if (save_cwd (&cwd)) - error_exit (); - - if (CVS_CHDIR (dir) < 0) - error (1, errno, "cannot change directory to %s", dir); - l = Entries_Open (0, NULL); - files_removed = walklist (l, isremoved, 0); - Entries_Close (l); - - if (restore_cwd (&cwd, NULL)) - error_exit (); - free_cwd (&cwd); - - if (files_removed != 0) - { - /* There are files that have been removed, but not - committed! Do not consider the directory empty. */ - (void) CVS_CLOSEDIR (dirp); - return 0; - } - } - } - errno = 0; - } - if (errno != 0) - { - error (0, errno, "cannot read directory %s", dir); - (void) CVS_CLOSEDIR (dirp); - return 0; - } - (void) CVS_CLOSEDIR (dirp); - return 1; -} - - - -/* - * scratch the Entries file entry associated with a file - */ -static int -scratch_file (finfo, vers) - struct file_info *finfo; - Vers_TS *vers; -{ - history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository); - Scratch_Entry (finfo->entries, finfo->file); -#ifdef SERVER_SUPPORT - if (server_active) - { - if (vers->ts_user == NULL) - server_scratch_entry_only (); - server_updated (finfo, vers, - SERVER_UPDATED, (mode_t) -1, - (unsigned char *) NULL, - (struct buffer *) NULL); - } -#endif - if (unlink_file (finfo->file) < 0 && ! existence_error (errno)) - error (0, errno, "unable to remove %s", finfo->fullname); - else if (!server_active) - { - /* skip this step when the server is running since - * server_updated should have handled it */ - /* keep the vers structure up to date in case we do a join - * - if there isn't a file, it can't very well have a version number, can it? - */ - if (vers->vn_user != NULL) - { - free (vers->vn_user); - vers->vn_user = NULL; - } - if (vers->ts_user != NULL) - { - free (vers->ts_user); - vers->ts_user = NULL; - } - } - return 0; -} - - - -/* - * Check out a file. - */ -static int -checkout_file (finfo, vers_ts, adding, merging, update_server) - struct file_info *finfo; - Vers_TS *vers_ts; - int adding; - int merging; - int update_server; -{ - char *backup; - int set_time, retval = 0; - int status; - int file_is_dead; - struct buffer *revbuf; - - backup = NULL; - revbuf = NULL; - - /* Don't screw with backup files if we're going to stdout, or if - we are the server. */ - if (!pipeout && !server_active) - { - backup = xmalloc (strlen (finfo->file) - + sizeof (CVSADM) - + sizeof (CVSPREFIX) - + 10); - (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file); - if (isfile (finfo->file)) - rename_file (finfo->file, backup); - else - { - /* If -f/-t wrappers are being used to wrap up a directory, - then backup might be a directory instead of just a file. */ - if (unlink_file_dir (backup) < 0) - { - /* Not sure if the existence_error check is needed here. */ - if (!existence_error (errno)) - /* FIXME: should include update_dir in message. */ - error (0, errno, "error removing %s", backup); - } - free (backup); - backup = NULL; - } - } - - file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs); - - if (!file_is_dead) - { - /* - * if we are checking out to stdout, print a nice message to - * stderr, and add the -p flag to the command */ - if (pipeout) - { - if (!quiet) - { - cvs_outerr ("\ -===================================================================\n\ -Checking out ", 0); - cvs_outerr (finfo->fullname, 0); - cvs_outerr ("\n\ -RCS: ", 0); - cvs_outerr (vers_ts->srcfile->path, 0); - cvs_outerr ("\n\ -VERS: ", 0); - cvs_outerr (vers_ts->vn_rcs, 0); - cvs_outerr ("\n***************\n", 0); - } - } - -#ifdef SERVER_SUPPORT - if (update_server - && server_active - && ! pipeout - && ! file_gzip_level - && ! joining () - && ! wrap_name_has (finfo->file, WRAP_FROMCVS)) - { - revbuf = buf_nonio_initialize ((BUFMEMERRPROC) NULL); - status = RCS_checkout (vers_ts->srcfile, (char *) NULL, - vers_ts->vn_rcs, vers_ts->tag, - vers_ts->options, RUN_TTY, - checkout_to_buffer, revbuf); - } - else -#endif - status = RCS_checkout (vers_ts->srcfile, - pipeout ? NULL : finfo->file, - vers_ts->vn_rcs, vers_ts->tag, - vers_ts->options, RUN_TTY, - (RCSCHECKOUTPROC) NULL, (void *) NULL); - } - if (file_is_dead || status == 0) - { - mode_t mode; - - mode = (mode_t) -1; - - if (!pipeout) - { - Vers_TS *xvers_ts; - - if (revbuf != NULL && !noexec) - { - struct stat sb; - - /* FIXME: We should have RCS_checkout return the mode. - That would also fix the kludge with noexec, above, which - is here only because noexec doesn't write srcfile->path - for us to stat. */ - if (stat (vers_ts->srcfile->path, &sb) < 0) - { -#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) - buf_free (revbuf); -#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */ - error (1, errno, "cannot stat %s", - vers_ts->srcfile->path); - } - mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH); - } - - if (cvswrite - && !file_is_dead - && !fileattr_get (finfo->file, "_watched")) - { - if (revbuf == NULL) - xchmod (finfo->file, 1); - else - { - /* We know that we are the server here, so - although xchmod checks umask, we don't bother. */ - mode |= (((mode & S_IRUSR) ? S_IWUSR : 0) - | ((mode & S_IRGRP) ? S_IWGRP : 0) - | ((mode & S_IROTH) ? S_IWOTH : 0)); - } - } - - { - /* A newly checked out file is never under the spell - of "cvs edit". If we think we were editing it - from a previous life, clean up. Would be better to - check for same the working directory instead of - same user, but that is hairy. */ - - struct addremove_args args; - - editor_set (finfo->file, getcaller (), NULL); - - memset (&args, 0, sizeof args); - args.remove_temp = 1; - watch_modify_watchers (finfo->file, &args); - } - - /* set the time from the RCS file iff it was unknown before */ - set_time = - (!noexec - && (vers_ts->vn_user == NULL || - strncmp (vers_ts->ts_rcs, "Initial", 7) == 0) - && !file_is_dead); - - wrap_fromcvs_process_file (finfo->file); - - xvers_ts = Version_TS (finfo, options, tag, date, - force_tag_match, set_time); - if (strcmp (xvers_ts->options, "-V4") == 0) - xvers_ts->options[0] = '\0'; - - if (revbuf != NULL) - { - /* If we stored the file data into a buffer, then we - didn't create a file at all, so xvers_ts->ts_user - is wrong. The correct value is to have it be the - same as xvers_ts->ts_rcs, meaning that the working - file is unchanged from the RCS file. - - FIXME: We should tell Version_TS not to waste time - statting the nonexistent file. - - FIXME: Actually, I don't think the ts_user value - matters at all here. The only use I know of is - that it is printed in a trace message by - Server_Register. */ - - if (xvers_ts->ts_user != NULL) - free (xvers_ts->ts_user); - xvers_ts->ts_user = xstrdup (xvers_ts->ts_rcs); - } - - (void) time (&last_register_time); - - if (file_is_dead) - { - if (xvers_ts->vn_user != NULL) - { - error (0, 0, - "warning: %s is not (any longer) pertinent", - finfo->fullname); - } - Scratch_Entry (finfo->entries, finfo->file); -#ifdef SERVER_SUPPORT - if (server_active && xvers_ts->ts_user == NULL) - server_scratch_entry_only (); -#endif - /* FIXME: Rather than always unlink'ing, and ignoring the - existence_error, we should do the unlink only if - vers_ts->ts_user is non-NULL. Then there would be no - need to ignore an existence_error (for example, if the - user removes the file while we are running). */ - if (unlink_file (finfo->file) < 0 && ! existence_error (errno)) - { - error (0, errno, "cannot remove %s", finfo->fullname); - } - } - else - Register (finfo->entries, finfo->file, - adding ? "0" : xvers_ts->vn_rcs, - xvers_ts->ts_user, xvers_ts->options, - xvers_ts->tag, xvers_ts->date, - (char *)0); /* Clear conflict flag on fresh checkout */ - - /* fix up the vers structure, in case it is used by join */ - if (join_rev1) - { - /* FIXME: It seems like we should be preserving ts_user - * & ts_rcs here, but setting them causes problems in - * join_file(). - */ - if (vers_ts->vn_user != NULL) - free (vers_ts->vn_user); - if (vers_ts->vn_rcs != NULL) - free (vers_ts->vn_rcs); - vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs); - vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs); - } - - /* If this is really Update and not Checkout, recode history */ - if (strcmp (cvs_cmd_name, "update") == 0) - history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, finfo->file, - finfo->repository); - - freevers_ts (&xvers_ts); - - if (!really_quiet && !file_is_dead) - { - write_letter (finfo, 'U'); - } - } - -#ifdef SERVER_SUPPORT - if (update_server && server_active) - server_updated (finfo, vers_ts, - merging ? SERVER_MERGED : SERVER_UPDATED, - mode, (unsigned char *) NULL, revbuf); -#endif - } - else - { - if (backup != NULL) - { - rename_file (backup, finfo->file); - free (backup); - backup = NULL; - } - - error (0, 0, "could not check out %s", finfo->fullname); - - retval = status; - } - - if (backup != NULL) - { - /* If -f/-t wrappers are being used to wrap up a directory, - then backup might be a directory instead of just a file. */ - if (unlink_file_dir (backup) < 0) - { - /* Not sure if the existence_error check is needed here. */ - if (!existence_error (errno)) - /* FIXME: should include update_dir in message. */ - error (0, errno, "error removing %s", backup); - } - free (backup); - } - -#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) - if (revbuf != NULL) - buf_free (revbuf); -#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */ - return retval; -} - - - -#ifdef SERVER_SUPPORT - -/* This function is used to write data from a file being checked out - into a buffer. */ - -static void -checkout_to_buffer (callerdat, data, len) - void *callerdat; - const char *data; - size_t len; -{ - struct buffer *buf = (struct buffer *) callerdat; - - buf_output (buf, data, len); -} - -#endif /* SERVER_SUPPORT */ - -#ifdef SERVER_SUPPORT - -/* This structure is used to pass information between patch_file and - patch_file_write. */ - -struct patch_file_data -{ - /* File name, for error messages. */ - const char *filename; - /* File to which to write. */ - FILE *fp; - /* Whether to compute the MD5 checksum. */ - int compute_checksum; - /* Data structure for computing the MD5 checksum. */ - struct cvs_MD5Context context; - /* Set if the file has a final newline. */ - int final_nl; -}; - -/* Patch a file. Runs diff. This is only done when running as the - * server. The hope is that the diff will be smaller than the file - * itself. - */ -static int -patch_file (finfo, vers_ts, docheckout, file_info, checksum) - struct file_info *finfo; - Vers_TS *vers_ts; - int *docheckout; - struct stat *file_info; - unsigned char *checksum; -{ - char *backup; - char *file1; - char *file2; - int retval = 0; - int retcode = 0; - int fail; - FILE *e; - struct patch_file_data data; - - *docheckout = 0; - - if (noexec || pipeout || joining ()) - { - *docheckout = 1; - return 0; - } - - /* If this file has been marked as being binary, then never send a - patch. */ - if (strcmp (vers_ts->options, "-kb") == 0) - { - *docheckout = 1; - return 0; - } - - /* First check that the first revision exists. If it has been nuked - by cvs admin -o, then just fall back to checking out entire - revisions. In some sense maybe we don't have to do this; after - all cvs.texinfo says "Make sure that no-one has checked out a - copy of the revision you outdate" but then again, that advice - doesn't really make complete sense, because "cvs admin" operates - on a working directory and so _someone_ will almost always have - _some_ revision checked out. */ - { - char *rev; - - rev = RCS_gettag (finfo->rcs, vers_ts->vn_user, 1, NULL); - if (rev == NULL) - { - *docheckout = 1; - return 0; - } - else - free (rev); - } - - /* If the revision is dead, let checkout_file handle it rather - than duplicating the processing here. */ - if (RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs)) - { - *docheckout = 1; - return 0; - } - - backup = xmalloc (strlen (finfo->file) - + sizeof (CVSADM) - + sizeof (CVSPREFIX) - + 10); - (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file); - if (isfile (finfo->file)) - rename_file (finfo->file, backup); - else - { - if (unlink_file (backup) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", backup); - } - - file1 = xmalloc (strlen (finfo->file) - + sizeof (CVSADM) - + sizeof (CVSPREFIX) - + 10); - (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file); - file2 = xmalloc (strlen (finfo->file) - + sizeof (CVSADM) - + sizeof (CVSPREFIX) - + 10); - (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file); - - fail = 0; - - /* We need to check out both revisions first, to see if either one - has a trailing newline. Because of this, we don't use rcsdiff, - but just use diff. */ - - e = CVS_FOPEN (file1, "w"); - if (e == NULL) - error (1, errno, "cannot open %s", file1); - - data.filename = file1; - data.fp = e; - data.final_nl = 0; - data.compute_checksum = 0; - - /* Duplicating the client working file, so use the original sticky options. - */ - retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL, - vers_ts->vn_user, vers_ts->entdata->tag, - vers_ts->entdata->options, RUN_TTY, - patch_file_write, (void *) &data); - - if (fclose (e) < 0) - error (1, errno, "cannot close %s", file1); - - if (retcode != 0 || ! data.final_nl) - fail = 1; - - if (! fail) - { - e = CVS_FOPEN (file2, "w"); - if (e == NULL) - error (1, errno, "cannot open %s", file2); - - data.filename = file2; - data.fp = e; - data.final_nl = 0; - data.compute_checksum = 1; - cvs_MD5Init (&data.context); - - retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL, - vers_ts->vn_rcs, vers_ts->tag, - vers_ts->options, RUN_TTY, - patch_file_write, (void *) &data); - - if (fclose (e) < 0) - error (1, errno, "cannot close %s", file2); - - if (retcode != 0 || ! data.final_nl) - fail = 1; - else - cvs_MD5Final (checksum, &data.context); - } - - retcode = 0; - if (! fail) - { - int dargc = 0; - size_t darg_allocated = 0; - char **dargv = NULL; - - /* If the client does not support the Rcs-diff command, we - send a context diff, and the client must invoke patch. - That approach was problematical for various reasons. The - new approach only requires running diff in the server; the - client can handle everything without invoking an external - program. */ - if (!rcs_diff_patches) - /* We use -c, not -u, because that is what CVS has - traditionally used. Kind of a moot point, now that - Rcs-diff is preferred, so there is no point in making - the compatibility issues worse. */ - run_add_arg_p (&dargc, &darg_allocated, &dargv, "-c"); - else - /* Now that diff is librarified, we could be passing -a if - we wanted to. However, it is unclear to me whether we - would want to. Does diff -a, in any significant - percentage of cases, produce patches which are smaller - than the files it is patching? I guess maybe text - files with character sets which diff regards as - 'binary'. Conversely, do they tend to be much larger - in the bad cases? This needs some more - thought/investigation, I suspect. */ - run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n"); - retcode = diff_exec (file1, file2, NULL, NULL, dargc, dargv, - finfo->file); - run_arg_free_p (dargc, dargv); - free (dargv); - - /* A retcode of 0 means no differences. 1 means some differences. */ - if (retcode != 0 - && retcode != 1) - { - fail = 1; - } - } - - if (! fail) - { - struct stat file2_info; - - /* Check to make sure the patch is really shorter */ - if (CVS_STAT (file2, &file2_info) < 0) - error (1, errno, "could not stat %s", file2); - if (CVS_STAT (finfo->file, file_info) < 0) - error (1, errno, "could not stat %s", finfo->file); - if (file2_info.st_size <= file_info->st_size) - fail = 1; - } - - if (! fail) - { -# define BINARY "Binary" - char buf[sizeof BINARY]; - unsigned int c; - - /* Check the diff output to make sure patch will be handle it. */ - e = CVS_FOPEN (finfo->file, "r"); - if (e == NULL) - error (1, errno, "could not open diff output file %s", - finfo->fullname); - c = fread (buf, 1, sizeof BINARY - 1, e); - buf[c] = '\0'; - if (strcmp (buf, BINARY) == 0) - { - /* These are binary files. We could use diff -a, but - patch can't handle that. */ - fail = 1; - } - fclose (e); - } - - if (! fail) - { - Vers_TS *xvers_ts; - - /* Stat the original RCS file, and then adjust it the way - that RCS_checkout would. FIXME: This is an abstraction - violation. */ - if (CVS_STAT (vers_ts->srcfile->path, file_info) < 0) - error (1, errno, "could not stat %s", vers_ts->srcfile->path); - if (chmod (finfo->file, - file_info->st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH)) - < 0) - error (0, errno, "cannot change mode of file %s", finfo->file); - if (cvswrite - && !fileattr_get (finfo->file, "_watched")) - xchmod (finfo->file, 1); - - /* This stuff is just copied blindly from checkout_file. I - don't really know what it does. */ - xvers_ts = Version_TS (finfo, options, tag, date, - force_tag_match, 0); - if (strcmp (xvers_ts->options, "-V4") == 0) - xvers_ts->options[0] = '\0'; - - Register (finfo->entries, finfo->file, xvers_ts->vn_rcs, - xvers_ts->ts_user, xvers_ts->options, - xvers_ts->tag, xvers_ts->date, NULL); - - if (CVS_STAT (finfo->file, file_info) < 0) - error (1, errno, "could not stat %s", finfo->file); - - /* If this is really Update and not Checkout, record history. */ - if (strcmp (cvs_cmd_name, "update") == 0) - history_write ('P', finfo->update_dir, xvers_ts->vn_rcs, - finfo->file, finfo->repository); - - freevers_ts (&xvers_ts); - - if (!really_quiet) - { - write_letter (finfo, 'P'); - } - } - else - { - int old_errno = errno; /* save errno value over the rename */ - - if (isfile (backup)) - rename_file (backup, finfo->file); - - if (retcode != 0 && retcode != 1) - error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0, - "could not diff %s", finfo->fullname); - - *docheckout = 1; - retval = retcode; - } - - if (unlink_file (backup) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", backup); - if (unlink_file (file1) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", file1); - if (unlink_file (file2) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", file2); - - free (backup); - free (file1); - free (file2); - return retval; -} - - - -/* Write data to a file. Record whether the last byte written was a - newline. Optionally compute a checksum. This is called by - patch_file via RCS_checkout. */ - -static void -patch_file_write (callerdat, buffer, len) - void *callerdat; - const char *buffer; - size_t len; -{ - struct patch_file_data *data = (struct patch_file_data *) callerdat; - - if (fwrite (buffer, 1, len, data->fp) != len) - error (1, errno, "cannot write %s", data->filename); - - data->final_nl = (buffer[len - 1] == '\n'); - - if (data->compute_checksum) - cvs_MD5Update (&data->context, (unsigned char *) buffer, len); -} - -#endif /* SERVER_SUPPORT */ - -/* - * Several of the types we process only print a bit of information consisting - * of a single letter and the name. - */ -void -write_letter (finfo, letter) - struct file_info *finfo; - int letter; -{ - if (!really_quiet) - { - char *tag = NULL; - /* Big enough for "+updated" or any of its ilk. */ - char buf[80]; - - switch (letter) - { - case 'U': - tag = "updated"; - break; - default: - /* We don't yet support tagged output except for "U". */ - break; - } - - if (tag != NULL) - { - sprintf (buf, "+%s", tag); - cvs_output_tagged (buf, NULL); - } - buf[0] = letter; - buf[1] = ' '; - buf[2] = '\0'; - cvs_output_tagged ("text", buf); - cvs_output_tagged ("fname", finfo->fullname); - cvs_output_tagged ("newline", NULL); - if (tag != NULL) - { - sprintf (buf, "-%s", tag); - cvs_output_tagged (buf, NULL); - } - } - return; -} - - - -/* Reregister a file after a merge. */ -static void -RegisterMerge PROTO((struct file_info *finfo, Vers_TS *vers, - const char *backup, int has_conflicts)); -static void -RegisterMerge (finfo, vers, backup, has_conflicts) - struct file_info *finfo; - Vers_TS *vers; - const char *backup; - int has_conflicts; -{ - /* This file is the result of a merge, which means that it has - been modified. We use a special timestamp string which will - not compare equal to any actual timestamp. */ - char *cp = NULL; - - if (has_conflicts) - { - time (&last_register_time); - cp = time_stamp (finfo->file); - } - 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); - -#ifdef SERVER_SUPPORT - /* Send the new contents of the file before the message. If we - wanted to be totally correct, we would have the client write - the message only after the file has safely been written. */ - if (server_active) - { - server_copy_file (finfo->file, finfo->update_dir, finfo->repository, - backup); - server_updated (finfo, vers, SERVER_MERGED, (mode_t) -1, NULL, NULL); - } -#endif -} - - - -/* - * Do all the magic associated with a file which needs to be merged - */ -static int -merge_file (finfo, vers) - struct file_info *finfo; - Vers_TS *vers; -{ - char *backup; - int status; - int retcode = 0; - int retval; - - assert (vers->vn_user); - - /* - * The users currently modified file is moved to a backup file name - * ".#filename.version", so that it will stay around for a few days - * before being automatically removed by some cron daemon. The "version" - * is the version of the file that the user was most up-to-date with - * before the merge. - */ - backup = xmalloc (strlen (finfo->file) - + strlen (vers->vn_user) - + sizeof (BAKPREFIX) - + 10); - (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user); - - if (unlink_file (backup) && !existence_error (errno)) - error (0, errno, "unable to remove %s", backup); - copy_file (finfo->file, backup); - xchmod (finfo->file, 1); - - if (strcmp (vers->options, "-kb") == 0 - || wrap_merge_is_copy (finfo->file) - || special_file_mismatch (finfo, NULL, vers->vn_rcs)) - { - /* For binary files, a merge is always a conflict. Same for - files whose permissions or linkage do not match. We give the - user 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. */ - - /* TODO: it may not always be necessary to regard a permission - mismatch as a conflict. The working file and the RCS file - have a common ancestor `A'; if the working file's permissions - match A's, then it's probably safe to overwrite them with the - RCS permissions. Only if the working file, the RCS file, and - A all disagree should this be considered a conflict. But more - thought needs to go into this, and in the meantime it is safe - to treat any such mismatch as an automatic conflict. -twp */ - - retcode = RCS_checkout (finfo->rcs, finfo->file, - vers->vn_rcs, vers->tag, - vers->options, NULL, NULL, NULL); - if (retcode) - { - error (0, 0, "failed to check out `%s' file", finfo->fullname); - error (0, 0, "restoring `%s' from backup file `%s'", - finfo->fullname, backup); - rename_file (backup, finfo->file); - retval = 1; - goto out; - } - xchmod (finfo->file, 1); - - RegisterMerge (finfo, vers, backup, 1); - - /* Is there a better term than "nonmergeable file"? What we - really mean is, not something that CVS cannot or does not - want to merge (there might be an external manual or - automatic merge process). */ - error (0, 0, "nonmergeable file needs merge"); - error (0, 0, "revision %s from repository is now in %s", - vers->vn_rcs, finfo->fullname); - error (0, 0, "file from working directory is now in %s", backup); - write_letter (finfo, 'C'); - - history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file, - finfo->repository); - retval = 0; - goto out; - } - - status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file, - vers->options, vers->vn_user, vers->vn_rcs); - if (status != 0 && status != 1) - { - error (0, status == -1 ? errno : 0, - "could not merge revision %s of %s", vers->vn_user, finfo->fullname); - error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s", - finfo->fullname, backup); - rename_file (backup, finfo->file); - retval = 1; - goto out; - } - - if (strcmp (vers->options, "-V4") == 0) - vers->options[0] = '\0'; - - /* fix up the vers structure, in case it is used by join */ - if (join_rev1) - { - /* FIXME: Throwing away the original revision info is almost - certainly wrong -- what if join_rev1 is "BASE"? */ - if (vers->vn_user != NULL) - free (vers->vn_user); - vers->vn_user = xstrdup (vers->vn_rcs); - } - - RegisterMerge (finfo, vers, backup, status); - - /* FIXME: the noexec case is broken. RCS_merge could be doing the - xcmp on the temporary files without much hassle, I think. */ - if (!noexec && !xcmp (backup, finfo->file)) - { - cvs_output (finfo->fullname, 0); - cvs_output (" already contains the differences between ", 0); - cvs_output (vers->vn_user, 0); - cvs_output (" and ", 0); - cvs_output (vers->vn_rcs, 0); - cvs_output ("\n", 1); - - history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file, - finfo->repository); - retval = 0; - goto out; - } - - if (status == 1) - { - error (0, 0, "conflicts found in %s", finfo->fullname); - - write_letter (finfo, 'C'); - - history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file, - finfo->repository); - - } - else if (retcode == -1) - { - error (1, errno, "fork failed while examining update of %s", - finfo->fullname); - } - else - { - write_letter (finfo, 'M'); - history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file, - finfo->repository); - } - retval = 0; - out: - free (backup); - return retval; -} - - - -/* - * Do all the magic associated with a file which needs to be joined - * (reached via the -j option to checkout or update). - * - * INPUTS - * finfo File information about the destination file. - * vers The Vers_TS structure for finfo. - * - * GLOBALS - * join_rev1 From the command line. - * join_rev2 From the command line. - * server_active Natch. - * - * ASSUMPTIONS - * 1. Is not called in client mode. - */ -static void -join_file (finfo, vers) - struct file_info *finfo; - Vers_TS *vers; -{ - char *backup; - char *t_options; - int status; - - char *rev1; - char *rev2; - char *jrev1; - char *jrev2; - char *jdate1; - char *jdate2; - - if (trace) - fprintf (stderr, "%s-> join_file(%s, %s%s%s%s, %s, %s)\n", - CLIENT_SERVER_STR, - finfo->file, - vers->tag ? vers->tag : "", - vers->tag ? " (" : "", - vers->vn_rcs ? vers->vn_rcs : "", - vers->tag ? ")" : "", - join_rev1 ? join_rev1 : "", - join_rev2 ? join_rev2 : ""); - - jrev1 = join_rev1; - jrev2 = join_rev2; - jdate1 = date_rev1; - jdate2 = date_rev2; - - /* Determine if we need to do anything at all. */ - if (vers->srcfile == NULL || - vers->srcfile->path == NULL) - { - return; - } - - /* If only one join revision is specified, it becomes the second - revision. */ - if (jrev2 == NULL) - { - jrev2 = jrev1; - jrev1 = NULL; - jdate2 = jdate1; - jdate1 = NULL; - } - - /* FIXME: Need to handle "BASE" for jrev1 and/or jrev2. Note caveat - below about vn_user. */ - - /* Convert the second revision, walking branches and dates. */ - rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, (int *) NULL); - - /* If this is a merge of two revisions, get the first revision. - If only one join tag was specified, then the first revision is - the greatest common ancestor of the second revision and the - working file. */ - if (jrev1 != NULL) - rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, (int *) NULL); - else - { - /* Note that we use vn_rcs here, since vn_user may contain a - special string such as "-nn". */ - if (vers->vn_rcs == NULL) - rev1 = NULL; - else if (rev2 == NULL) - { - /* This means that the file never existed on the branch. - It does not mean that the file was removed on the - branch: that case is represented by a dead rev2. If - the file never existed on the branch, then we have - nothing to merge, so we just return. */ - return; - } - else - rev1 = gca (vers->vn_rcs, rev2); - } - - /* Handle a nonexistent or dead merge target. */ - if (rev2 == NULL || RCS_isdead (vers->srcfile, rev2)) - { - char *mrev; - short conflict = 0; - - if (rev2 != NULL) - free (rev2); - - /* If the first revision doesn't exist either, then there is - no change between the two revisions, so we don't do - anything. */ - if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1)) - { - if (rev1 != NULL) - free (rev1); - return; - } - - /* If we are merging two revisions, then the file was removed - between the first revision and the second one. In this - case we want to mark the file for removal. - - If we are merging one revision, then the file has been - removed between the greatest common ancestor and the merge - revision. From the perspective of the branch on to which - we ar emerging, which may be the trunk, either 1) the file - does not currently exist on the target, or 2) the file has - not been modified on the target branch since the greatest - common ancestor, or 3) the file has been modified on the - target branch since the greatest common ancestor. In case - 1 there is nothing to do. In case 2 we mark the file for - removal. In case 3 we have a conflict. - - Note that the handling is slightly different depending upon - whether one or two join targets were specified. If two - join targets were specified, we don't check whether the - file was modified since a given point. My reasoning is - that if you ask for an explicit merge between two tags, - then you want to merge in whatever was changed between - those two tags. If a file was removed between the two - tags, then you want it to be removed. However, if you ask - for a merge of a branch, then you want to merge in all - changes which were made on the branch. If a file was - removed on the branch, that is a change to the file. If - the file was also changed on the main line, then that is - also a change. These two changes--the file removal and the - modification--must be merged. This is a conflict. */ - - /* If the user file is dead, or does not exist, or has been - marked for removal, then there is nothing to do. */ - if (vers->vn_user == NULL - || vers->vn_user[0] == '-' - || RCS_isdead (vers->srcfile, vers->vn_user)) - { - free (rev1); - return; - } - - /* If the user file has been marked for addition, or has been - locally modified, then we have a conflict which we can not - resolve. No_Difference will already have been called in - this case, so comparing the timestamps is sufficient to - determine whether the file is locally modified. */ - if (/* may have changed on destination branch */ - /* file added locally */ - !strcmp (vers->vn_user, "0") - || /* destination branch modified in repository */ - strcmp (rev1, vers->vn_user) - || /* locally modified */ - vers->ts_user && strcmp (vers->ts_user, vers->ts_rcs)) - { - /* The removal should happen if either the file has never changed - * on the destination or the file has changed to be identical to - * the first join revision. - * - * ------R-----------D - * | - * \----J1---J2-----S - * - * So: - * - * J2 is dead. - * D is destination. - * R is source branch root/GCA. - * if J1 == D removal should happen - * if D == R removal should happen - * otherwise, fail. - * - * (In the source, J2 = REV2, D = user file (potentially VN_USER), - * R = GCA computed below) - */ - char *gca_rev1 = gca (rev1, vers->vn_user); -#ifdef SERVER_SUPPORT - if (server_active && !isreadable (finfo->file)) - { - int retcode; - /* The file is up to date. Need to check out the current - * contents. - */ - /* FIXME - see the FIXME comment above the call to RCS_checkout - * in the patch_file function. - */ - retcode = RCS_checkout (vers->srcfile, finfo->file, - vers->vn_user, vers->tag, - NULL, RUN_TTY, NULL, NULL); - if (retcode) - error (1, 0, - "failed to check out %s file", finfo->fullname); - } -#endif - if (/* genuinely changed on destination branch */ - RCS_cmp_file (vers->srcfile, gca_rev1, NULL, - NULL, vers->options, finfo->file) - && /* genuinely different from REV1 */ - RCS_cmp_file (vers->srcfile, rev1, NULL, - NULL, vers->options, finfo->file)) - conflict = 1; - } - - free (rev1); - - if (conflict) - { - char *cp; - - if (jdate2) - error (0, 0, - "file %s has been removed in revision %s as of %s, but the destination is incompatibly modified", - finfo->fullname, jrev2, jdate2); - else - error (0, 0, - "file %s has been removed in revision %s, but the destination is incompatibly modified", - finfo->fullname, jrev2); - - /* Register the conflict with the client. */ - - /* FIXME: vers->ts_user should always be set here but sometimes - * isn't, namely when checkout_file() has just created the file, - * but simply setting it in checkout_file() appears to cause other - * problems. - */ - if (isfile (finfo->file)) - cp = time_stamp (finfo->file); - else - cp = xstrdup (vers->ts_user); - - Register (finfo->entries, finfo->file, vers->vn_user, - "Result of merge", vers->options, vers->tag, vers->date, - cp); - write_letter (finfo, 'C'); - free (cp); - -#ifdef SERVER_SUPPORT - /* Abuse server_checked_in() to send the updated entry without - * needing to update the file. - */ - if (server_active) - server_checked_in (finfo->file, finfo->update_dir, - finfo->repository); -#endif - - return; - } - - /* The user file exists and has not been modified. Mark it - for removal. FIXME: If we are doing a checkout, this has - the effect of first checking out the file, and then - removing it. It would be better to just register the - removal. - - The same goes for a removal then an add. e.g. - cvs up -rbr -jbr2 could remove and readd the same file - */ - /* save the rev since server_updated might invalidate it */ - mrev = xmalloc (strlen (vers->vn_user) + 2); - sprintf (mrev, "-%s", vers->vn_user); -#ifdef SERVER_SUPPORT - if (server_active) - { - server_scratch (finfo->file); - server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1, - (unsigned char *) NULL, (struct buffer *) NULL); - } -#endif - Register (finfo->entries, finfo->file, mrev, vers->ts_rcs, - vers->options, vers->tag, vers->date, vers->ts_conflict); - free (mrev); - /* We need to check existence_error here because if we are - running as the server, and the file is up to date in the - working directory, the client will not have sent us a copy. */ - if (unlink_file (finfo->file) < 0 && ! existence_error (errno)) - error (0, errno, "cannot remove file %s", finfo->fullname); -#ifdef SERVER_SUPPORT - if (server_active) - server_checked_in (finfo->file, finfo->update_dir, - finfo->repository); -#endif - if (! really_quiet) - error (0, 0, "scheduling %s for removal", finfo->fullname); - - return; - } - - /* If the two merge revisions are the same, then there is nothing - * to do. This needs to be checked before the rev2 == up-to-date base - * revision check tha comes next. Otherwise, rev1 can == rev2 and get an - * "already contains the changes between <rev1> and <rev1>" message. - */ - if (rev1 && strcmp (rev1, rev2) == 0) - { - free (rev1); - free (rev2); - return; - } - - /* If we know that the user file is up-to-date, then it becomes an - * optimization to skip the merge when rev2 is the same as the base - * revision. i.e. we know that diff3(file2,file1,file2) will produce - * file2. - */ - if (vers->vn_user != NULL && vers->ts_user != NULL - && strcmp (vers->ts_user, vers->ts_rcs) == 0 - && strcmp (rev2, vers->vn_user) == 0) - { - if (!really_quiet) - { - cvs_output (finfo->fullname, 0); - cvs_output (" already contains the differences between ", 0); - cvs_output (rev1 ? rev1 : "creation", 0); - cvs_output (" and ", 0); - cvs_output (rev2, 0); - cvs_output ("\n", 1); - } - - if (rev1 != NULL) - free (rev1); - free (rev2); - - return; - } - - /* If rev1 is dead or does not exist, then the file was added - between rev1 and rev2. */ - if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1)) - { - if (rev1 != NULL) - free (rev1); - free (rev2); - - /* If the file does not exist in the working directory, then - we can just check out the new revision and mark it for - addition. */ - if (vers->vn_user == NULL) - { - char *saved_options = options; - Vers_TS *xvers; - - 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); - options = saved_options; - - freevers_ts (&xvers); - - return; - } - - /* The file currently exists in the working directory, so we - have a conflict which we can not resolve. Note that this - is true even if the file is marked for addition or removal. */ - - if (jdate2 != NULL) - error (0, 0, - "file %s exists, but has been added in revision %s as of %s", - finfo->fullname, jrev2, jdate2); - else - error (0, 0, - "file %s exists, but has been added in revision %s", - finfo->fullname, jrev2); - - return; - } - - /* If there is no working file, then we can't do the merge. */ - if (vers->vn_user == NULL || vers->vn_user[0] == '-') - { - free (rev1); - free (rev2); - - if (jdate2 != NULL) - error (0, 0, - "file %s does not exist, but is present in revision %s as of %s", - finfo->fullname, jrev2, jdate2); - else - error (0, 0, - "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? */ - - return; - } - -#ifdef SERVER_SUPPORT - if (server_active && !isreadable (finfo->file)) - { - int retcode; - /* The file is up to date. Need to check out the current contents. */ - /* FIXME - see the FIXME comment above the call to RCS_checkout in the - * patch_file function. - */ - retcode = RCS_checkout (vers->srcfile, finfo->file, - vers->vn_user, vers->tag, - (char *) NULL, RUN_TTY, - (RCSCHECKOUTPROC) NULL, (void *) NULL); - if (retcode != 0) - error (1, 0, - "failed to check out %s file", finfo->fullname); - } -#endif - - /* - * The users currently modified file is moved to a backup file name - * ".#filename.version", so that it will stay around for a few days - * before being automatically removed by some cron daemon. The "version" - * is the version of the file that the user was most up-to-date with - * before the merge. - */ - backup = xmalloc (strlen (finfo->file) - + strlen (vers->vn_user) - + sizeof (BAKPREFIX) - + 10); - (void) sprintf (backup, "%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user); - - if (unlink_file (backup) < 0 - && !existence_error (errno)) - error (0, errno, "cannot remove %s", backup); - copy_file (finfo->file, backup); - xchmod (finfo->file, 1); - - t_options = vers->options; -#if 0 - 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 - revision, then we can just RCS_checkout the target (no merging - as such). In the text file case, this is probably quite - similar to the RCS_merge, but in the binary file case, - RCS_merge gives all kinds of trouble. */ - if (vers->vn_user != NULL - && strcmp (rev1, vers->vn_user) == 0 - /* See comments above about how No_Difference has already been - called. */ - && vers->ts_user != NULL - && strcmp (vers->ts_user, vers->ts_rcs) == 0 - - /* Avoid this in the text file case. See below for why. - */ - && (strcmp (t_options, "-kb") == 0 - || wrap_merge_is_copy (finfo->file))) - { - /* FIXME: Verify my comment below: - * - * RCS_merge does nothing with keywords. It merges the changes between - * two revisions without expanding the keywords (it might expand in - * -kk mode before computing the diff between rev1 and rev2 - I'm not - * sure). In other words, the keyword lines in the current work file - * get left alone. - * - * Therfore, checking out the destination revision (rev2) is probably - * incorrect in the text case since we should see the keywords that were - * substituted into the original file at the time it was checked out - * and not the keywords from rev2. - * - * Also, it is safe to pass in NULL for nametag since we know no - * substitution is happening during the binary mode checkout. - */ - if (RCS_checkout ( finfo->rcs, finfo->file, rev2, (char *)NULL, t_options, - RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0 ) - status = 2; - else - status = 0; - - /* OK, this is really stupid. RCS_checkout carefully removes - write permissions, and we carefully put them back. But - until someone gets around to fixing it, that seems like the - easiest way to get what would seem to be the right mode. - I don't check CVSWRITE or _watched; I haven't thought about - that in great detail, but it seems like a watched file should - be checked out (writable) after a merge. */ - xchmod (finfo->file, 1); - - /* Traditionally, the text file case prints a whole bunch of - scary looking and verbose output which fails to tell the user - what is really going on (it gives them rev1 and rev2 but doesn't - indicate in any way that rev1 == vn_user). I think just a - simple "U foo" is good here; it seems analogous to the case in - which the file was added on the branch in terms of what to - print. */ - write_letter (finfo, 'U'); - } - else if (strcmp (t_options, "-kb") == 0 - || wrap_merge_is_copy (finfo->file) - || special_file_mismatch (finfo, rev1, rev2)) - { - /* We are dealing with binary files, or files with a - permission/linkage mismatch (this second case only occurs when - PRESERVE_PERMISSIONS_SUPPORT is enabled), and real merging would - need to take place. This is a conflict. We give the user - 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, (char *)NULL, - t_options, RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0) - status = 2; - else - status = 0; - - /* OK, this is really stupid. RCS_checkout carefully removes - write permissions, and we carefully put them back. But - until someone gets around to fixing it, that seems like the - easiest way to get what would seem to be the right mode. - I don't check CVSWRITE or _watched; I haven't thought about - that in great detail, but it seems like a watched file should - be checked out (writable) after a merge. */ - xchmod (finfo->file, 1); - - /* Hmm. We don't give them REV1 anywhere. I guess most people - probably don't have a 3-way merge tool for the file type in - question, and might just get confused if we tried to either - provide them with a copy of the file from REV1, or even just - told them what REV1 is so they can get it themself, but it - might be worth thinking about. */ - /* See comment in merge_file about the "nonmergeable file" - terminology. */ - error (0, 0, "nonmergeable file needs merge"); - error (0, 0, "revision %s from repository is now in %s", - rev2, finfo->fullname); - error (0, 0, "file from working directory is now in %s", backup); - write_letter (finfo, 'C'); - } - else - status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file, - t_options, rev1, rev2); - - if (status != 0) - { - if (status != 1) - { - error (0, status == -1 ? errno : 0, - "could not merge revision %s of %s", rev2, finfo->fullname); - error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s", - finfo->fullname, backup); - rename_file (backup, finfo->file); - } - } - else /* status == 0 */ - { - /* FIXME: the noexec case is broken. RCS_merge could be doing the - xcmp on the temporary files without much hassle, I think. */ - if (!noexec && !xcmp (backup, finfo->file)) - { - if (!really_quiet) - { - cvs_output (finfo->fullname, 0); - cvs_output (" already contains the differences between ", 0); - cvs_output (rev1, 0); - cvs_output (" and ", 0); - cvs_output (rev2, 0); - cvs_output ("\n", 1); - } - - /* and skip the registering and sending the new file since it - * hasn't been updated. - */ - goto out; - } - } - - /* The file has changed, but if we just checked it out it may - still have the same timestamp it did when it was first - registered above in checkout_file. We register it again with a - dummy timestamp to make sure that later runs of CVS will - recognize that it has changed. - - We don't actually need to register again if we called - RCS_checkout above, and we aren't running as the server. - However, that is not the normal case, and calling Register - again won't cost much in that case. */ - RegisterMerge (finfo, vers, backup, status); - -out: - free (rev1); - free (rev2); - free (backup); -} - - - -/* - * Report whether revisions REV1 and REV2 of FINFO agree on: - * . file ownership - * . permissions - * . major and minor device numbers - * . symbolic links - * . hard links - * - * If either REV1 or REV2 is NULL, the working copy is used instead. - * - * Return 1 if the files differ on these data. - */ - -int -special_file_mismatch (finfo, rev1, rev2) - struct file_info *finfo; - char *rev1; - char *rev2; -{ -#ifdef PRESERVE_PERMISSIONS_SUPPORT - struct stat sb; - RCSVers *vp; - Node *n; - uid_t rev1_uid, rev2_uid; - gid_t rev1_gid, rev2_gid; - mode_t rev1_mode, rev2_mode; - unsigned long dev_long; - dev_t rev1_dev, rev2_dev; - char *rev1_symlink = NULL; - char *rev2_symlink = NULL; - List *rev1_hardlinks = NULL; - List *rev2_hardlinks = NULL; - int check_uids, check_gids, check_modes; - int result; - - /* If we don't care about special file info, then - don't report a mismatch in any case. */ - if (!preserve_perms) - return 0; - - /* When special_file_mismatch is called from No_Difference, the - RCS file has been only partially parsed. We must read the - delta tree in order to compare special file info recorded in - the delta nodes. (I think this is safe. -twp) */ - if (finfo->rcs->flags & PARTIAL) - RCS_reparsercsfile (finfo->rcs, NULL, NULL); - - check_uids = check_gids = check_modes = 1; - - /* Obtain file information for REV1. If this is null, then stat - finfo->file and use that info. */ - /* If a revision does not know anything about its status, - then presumably it doesn't matter, and indicates no conflict. */ - - if (rev1 == NULL) - { - if (islink (finfo->file)) - rev1_symlink = xreadlink (finfo->file); - else - { -# ifdef HAVE_STRUCT_STAT_ST_RDEV - if (CVS_LSTAT (finfo->file, &sb) < 0) - error (1, errno, "could not get file information for %s", - finfo->file); - rev1_uid = sb.st_uid; - rev1_gid = sb.st_gid; - 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); - } - else - { - n = findnode (finfo->rcs->versions, rev1); - vp = n->data; - - n = findnode (vp->other_delta, "symlink"); - if (n != NULL) - rev1_symlink = xstrdup (n->data); - else - { - n = findnode (vp->other_delta, "owner"); - if (n == NULL) - check_uids = 0; /* don't care */ - else - rev1_uid = strtoul (n->data, NULL, 10); - - n = findnode (vp->other_delta, "group"); - if (n == NULL) - check_gids = 0; /* don't care */ - else - rev1_gid = strtoul (n->data, NULL, 10); - - n = findnode (vp->other_delta, "permissions"); - if (n == NULL) - check_modes = 0; /* don't care */ - else - rev1_mode = strtoul (n->data, NULL, 8); - - n = findnode (vp->other_delta, "special"); - if (n == NULL) - rev1_mode |= S_IFREG; - else - { - /* If the size of `ftype' changes, fix the sscanf call also */ - char ftype[16]; - if (sscanf (n->data, "%15s %lu", ftype, - &dev_long) < 2) - error (1, 0, "%s:%s has bad `special' newphrase %s", - finfo->file, rev1, (char *)n->data); - rev1_dev = dev_long; - if (strcmp (ftype, "character") == 0) - rev1_mode |= S_IFCHR; - else if (strcmp (ftype, "block") == 0) - rev1_mode |= S_IFBLK; - else - error (0, 0, "%s:%s unknown file type `%s'", - finfo->file, rev1, ftype); - } - - rev1_hardlinks = vp->hardlinks; - if (rev1_hardlinks == NULL) - rev1_hardlinks = getlist(); - } - } - - /* Obtain file information for REV2. */ - if (rev2 == NULL) - { - if (islink (finfo->file)) - rev2_symlink = xreadlink (finfo->file); - else - { -# ifdef HAVE_STRUCT_STAT_ST_RDEV - if (CVS_LSTAT (finfo->file, &sb) < 0) - error (1, errno, "could not get file information for %s", - finfo->file); - rev2_uid = sb.st_uid; - rev2_gid = sb.st_gid; - 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); - } - else - { - n = findnode (finfo->rcs->versions, rev2); - vp = n->data; - - n = findnode (vp->other_delta, "symlink"); - if (n != NULL) - rev2_symlink = xstrdup (n->data); - else - { - n = findnode (vp->other_delta, "owner"); - if (n == NULL) - check_uids = 0; /* don't care */ - else - rev2_uid = strtoul (n->data, NULL, 10); - - n = findnode (vp->other_delta, "group"); - if (n == NULL) - check_gids = 0; /* don't care */ - else - rev2_gid = strtoul (n->data, NULL, 10); - - n = findnode (vp->other_delta, "permissions"); - if (n == NULL) - check_modes = 0; /* don't care */ - else - rev2_mode = strtoul (n->data, NULL, 8); - - n = findnode (vp->other_delta, "special"); - if (n == NULL) - rev2_mode |= S_IFREG; - else - { - /* If the size of `ftype' changes, fix the sscanf call also */ - char ftype[16]; - if (sscanf (n->data, "%15s %lu", ftype, - &dev_long) < 2) - error (1, 0, "%s:%s has bad `special' newphrase %s", - finfo->file, rev2, (char *)n->data); - rev2_dev = dev_long; - if (strcmp (ftype, "character") == 0) - rev2_mode |= S_IFCHR; - else if (strcmp (ftype, "block") == 0) - rev2_mode |= S_IFBLK; - else - error (0, 0, "%s:%s unknown file type `%s'", - finfo->file, rev2, ftype); - } - - rev2_hardlinks = vp->hardlinks; - if (rev2_hardlinks == NULL) - rev2_hardlinks = getlist(); - } - } - - /* Check the user/group ownerships and file permissions, printing - an error for each mismatch found. Return 0 if all characteristics - matched, and 1 otherwise. */ - - result = 0; - - /* Compare symlinks first, since symlinks are simpler (don't have - any other characteristics). */ - if (rev1_symlink != NULL && rev2_symlink == NULL) - { - error (0, 0, "%s is a symbolic link", - (rev1 == NULL ? "working file" : rev1)); - result = 1; - } - else if (rev1_symlink == NULL && rev2_symlink != NULL) - { - error (0, 0, "%s is a symbolic link", - (rev2 == NULL ? "working file" : rev2)); - result = 1; - } - else if (rev1_symlink != NULL) - result = (strcmp (rev1_symlink, rev2_symlink) == 0); - else - { - /* Compare user ownership. */ - if (check_uids && rev1_uid != rev2_uid) - { - error (0, 0, "%s: owner mismatch between %s and %s", - finfo->file, - (rev1 == NULL ? "working file" : rev1), - (rev2 == NULL ? "working file" : rev2)); - result = 1; - } - - /* Compare group ownership. */ - if (check_gids && rev1_gid != rev2_gid) - { - error (0, 0, "%s: group mismatch between %s and %s", - finfo->file, - (rev1 == NULL ? "working file" : rev1), - (rev2 == NULL ? "working file" : rev2)); - result = 1; - } - - /* Compare permissions. */ - if (check_modes && - (rev1_mode & 07777) != (rev2_mode & 07777)) - { - error (0, 0, "%s: permission mismatch between %s and %s", - finfo->file, - (rev1 == NULL ? "working file" : rev1), - (rev2 == NULL ? "working file" : rev2)); - result = 1; - } - - /* Compare device file characteristics. */ - if ((rev1_mode & S_IFMT) != (rev2_mode & S_IFMT)) - { - error (0, 0, "%s: %s and %s are different file types", - finfo->file, - (rev1 == NULL ? "working file" : rev1), - (rev2 == NULL ? "working file" : rev2)); - result = 1; - } - else if (S_ISBLK (rev1_mode)) - { - if (rev1_dev != rev2_dev) - { - error (0, 0, "%s: device numbers of %s and %s do not match", - finfo->file, - (rev1 == NULL ? "working file" : rev1), - (rev2 == NULL ? "working file" : rev2)); - result = 1; - } - } - - /* Compare hard links. */ - if (compare_linkage_lists (rev1_hardlinks, rev2_hardlinks) == 0) - { - error (0, 0, "%s: hard linkage of %s and %s do not match", - finfo->file, - (rev1 == NULL ? "working file" : rev1), - (rev2 == NULL ? "working file" : rev2)); - result = 1; - } - } - - if (rev1_symlink != NULL) - free (rev1_symlink); - if (rev2_symlink != NULL) - free (rev2_symlink); - if (rev1_hardlinks != NULL) - dellist (&rev1_hardlinks); - if (rev2_hardlinks != NULL) - dellist (&rev2_hardlinks); - - return result; -#else - return 0; -#endif -} - - - -int -joining () -{ - return join_rev1 != NULL; -} diff --git a/contrib/cvs/src/update.h b/contrib/cvs/src/update.h deleted file mode 100644 index c886b4c..0000000 --- a/contrib/cvs/src/update.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Declarations for update.c. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -/* - * $FreeBSD$ - */ - -int do_update PROTO((int argc, char *argv[], char *xoptions, char *xtag, - char *xdate, int xforce, int local, int xbuild, - int xaflag, int xprune, int xpipeout, int which, - char *xjoin_rev1, char *xjoin_rev2, char *preload_update_dir, - int xpull_template, char *repository)); -int joining PROTO((void)); -extern int isemptydir PROTO ((const char *dir, int might_not_exist)); diff --git a/contrib/cvs/src/vers_ts.c b/contrib/cvs/src/vers_ts.c deleted file mode 100644 index 1bf880a..0000000 --- a/contrib/cvs/src/vers_ts.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - */ - -#include "cvs.h" - -#ifdef SERVER_SUPPORT -static void time_stamp_server PROTO((const char *, Vers_TS *, Entnode *)); -#endif - - - -/* Fill in and return a Vers_TS structure for the file FINFO. TAG and - DATE are from the command line. */ - -Vers_TS * -Version_TS (finfo, options, tag, date, force_tag_match, set_time) - struct file_info *finfo; - - /* Keyword expansion options, I think generally from the command - line. Can be either NULL or "" to indicate none are specified - here. */ - char *options; - char *tag; - char *date; - int force_tag_match; - int set_time; -{ - Node *p; - RCSNode *rcsdata; - Vers_TS *vers_ts; - struct stickydirtag *sdtp; - Entnode *entdata; - char *rcsexpand = NULL; - -#ifdef UTIME_EXPECTS_WRITABLE - int change_it_back = 0; -#endif - - /* get a new Vers_TS struct */ - vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS)); - memset ((char *) vers_ts, 0, sizeof (*vers_ts)); - - /* - * look up the entries file entry and fill in the version and timestamp - * if entries is NULL, there is no entries file so don't bother trying to - * look it up (used by checkout -P) - */ - if (finfo->entries == NULL) - { - sdtp = NULL; - p = NULL; - } - else - { - p = findnode_fn (finfo->entries, finfo->file); - sdtp = finfo->entries->list->data; /* list-private */ - } - - entdata = NULL; - if (p != NULL) - { - entdata = p->data; - - if (entdata->type == ENT_SUBDIR) - { - /* According to cvs.texinfo, the various fields in the Entries - file for a directory (other than the name) do not have a - defined meaning. We need to pass them along without getting - confused based on what is in them. Therefore we make sure - not to set vn_user and the like from Entries, add.c and - perhaps other code will expect these fields to be NULL for - a directory. */ - vers_ts->entdata = entdata; - } - else -#ifdef SERVER_SUPPORT - /* An entries line with "D" in the timestamp indicates that the - client sent Is-modified without sending Entry. So we want to - use the entries line for the sole purpose of telling - time_stamp_server what is up; we don't want the rest of CVS - to think there is an entries line. */ - if (strcmp (entdata->timestamp, "D") != 0) -#endif - { - vers_ts->vn_user = xstrdup (entdata->version); - vers_ts->ts_rcs = xstrdup (entdata->timestamp); - vers_ts->ts_conflict = xstrdup (entdata->conflict); - if (!(tag || date) && !(sdtp && sdtp->aflag)) - { - 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 == '\0') - { - if (!(sdtp && sdtp->aflag)) - vers_ts->options = xstrdup (entdata->options); - } - } - - /* Always look up the RCS keyword mode when we have an RCS archive. It - * will either be needed as a default or to avoid allowing the -k options - * specified on the command line from overriding binary mode (-kb). - */ - if (finfo->rcs != NULL) - rcsexpand = RCS_getexpand (finfo->rcs); - - /* - * -k options specified on the command line override (and overwrite) - * options stored in the entries file and default options from the RCS - * archive, except for binary mode (-kb). - */ - if (options && *options != '\0') - { - if (vers_ts->options != NULL) - free (vers_ts->options); - if (rcsexpand != NULL && strcmp (rcsexpand, "b") == 0) - vers_ts->options = xstrdup ("-kb"); - else - vers_ts->options = xstrdup (options); - } - else if ((!vers_ts->options || *vers_ts->options == '\0') - && rcsexpand != NULL) - { - /* If no keyword expansion was specified on command line, - use whatever was in the rcs file (if there is one). This - is how we, if we are the server, tell the client whether - a file is binary. */ - 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); - } - if (!vers_ts->options) - vers_ts->options = xstrdup (""); - - /* - * if tags were specified on the command line, they override what is in - * the Entries file - */ - if (tag || date) - { - vers_ts->tag = xstrdup (tag); - vers_ts->date = xstrdup (date); - } - else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0)) - { - if (!vers_ts->tag) - { - vers_ts->tag = xstrdup (sdtp->tag); - vers_ts->nonbranch = sdtp->nonbranch; - } - if (!vers_ts->date) - vers_ts->date = xstrdup (sdtp->date); - } - - /* Now look up the info on the source controlled file */ - if (finfo->rcs != NULL) - { - rcsdata = finfo->rcs; - rcsdata->refcount++; - } - else if (finfo->repository != NULL) - rcsdata = RCS_parse (finfo->file, finfo->repository); - else - rcsdata = NULL; - - if (rcsdata != NULL) - { - /* squirrel away the rcsdata pointer for others */ - vers_ts->srcfile = rcsdata; - - if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0) - { - vers_ts->vn_rcs = xstrdup (vers_ts->vn_user); - vers_ts->vn_tag = xstrdup (vers_ts->vn_user); - } - else - { - int simple; - - vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag, - vers_ts->date, force_tag_match, - &simple); - if (vers_ts->vn_rcs == NULL) - vers_ts->vn_tag = NULL; - else if (simple) - vers_ts->vn_tag = xstrdup (vers_ts->tag); - else - vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs); - } - - /* - * If the source control file exists and has the requested revision, - * get the Date the revision was checked in. If "user" exists, set - * its mtime. - */ - if (set_time && vers_ts->vn_rcs != NULL) - { -#ifdef SERVER_SUPPORT - if (server_active) - server_modtime (finfo, vers_ts); - else -#endif - { - struct utimbuf t; - - memset (&t, 0, sizeof (t)); - t.modtime = RCS_getrevtime (rcsdata, vers_ts->vn_rcs, 0, 0); - if (t.modtime != (time_t) -1) - { - (void) time (&t.actime); - -#ifdef UTIME_EXPECTS_WRITABLE - if (!iswritable (finfo->file)) - { - xchmod (finfo->file, 1); - change_it_back = 1; - } -#endif /* UTIME_EXPECTS_WRITABLE */ - - /* This used to need to ignore existence_errors - (for cases like where update.c now clears - set_time if noexec, but didn't used to). I - think maybe now it doesn't (server_modtime does - not like those kinds of cases). */ - (void) utime (finfo->file, &t); - -#ifdef UTIME_EXPECTS_WRITABLE - if (change_it_back) - { - xchmod (finfo->file, 0); - change_it_back = 0; - } -#endif /* UTIME_EXPECTS_WRITABLE */ - } - } - } - } - - /* get user file time-stamp in ts_user */ - if (finfo->entries != (List *) NULL) - { -#ifdef SERVER_SUPPORT - if (server_active) - time_stamp_server (finfo->file, vers_ts, entdata); - else -#endif - vers_ts->ts_user = time_stamp (finfo->file); - } - - return (vers_ts); -} - -#ifdef SERVER_SUPPORT - -/* Set VERS_TS->TS_USER to time stamp for FILE. */ - -/* Separate these out to keep the logic below clearer. */ -#define mark_lost(V) ((V)->ts_user = 0) -#define mark_unchanged(V) ((V)->ts_user = xstrdup ((V)->ts_rcs)) - -static void -time_stamp_server (file, vers_ts, entdata) - const char *file; - Vers_TS *vers_ts; - Entnode *entdata; -{ - struct stat sb; - char *cp; - - if (CVS_LSTAT (file, &sb) < 0) - { - if (! existence_error (errno)) - error (1, errno, "cannot stat temp file"); - - /* Missing file means lost or unmodified; check entries - file to see which. - - XXX FIXME - If there's no entries file line, we - wouldn't be getting the file at all, so consider it - lost. I don't know that that's right, but it's not - clear to me that either choice is. Besides, would we - have an RCS string in that case anyways? */ - if (entdata == NULL) - mark_lost (vers_ts); - else if (entdata->timestamp - && entdata->timestamp[0] == '=') - mark_unchanged (vers_ts); - else if (entdata->conflict - && entdata->conflict[0] == '=') - { - /* These just need matching content. Might as well minimize it. */ - vers_ts->ts_user = xstrdup (""); - vers_ts->ts_conflict = xstrdup (""); - } - else if (entdata->timestamp - && (entdata->timestamp[0] == 'M' - || entdata->timestamp[0] == 'D') - && entdata->timestamp[1] == '\0') - vers_ts->ts_user = xstrdup ("Is-modified"); - else - mark_lost (vers_ts); - } - else if (sb.st_mtime == 0) - { - /* We shouldn't reach this case any more! */ - abort (); - } - else - { - struct tm *tm_p; - - vers_ts->ts_user = xmalloc (25); - /* We want to use the same timestamp format as is stored in the - st_mtime. For unix (and NT I think) this *must* be universal - time (UT), so that files don't appear to be modified merely - because the timezone has changed. For VMS, or hopefully other - systems where gmtime returns NULL, the modification time is - stored in local time, and therefore it is not possible to cause - st_mtime to be out of sync by changing the timezone. */ - tm_p = gmtime (&sb.st_mtime); - cp = tm_p ? asctime (tm_p) : ctime (&sb.st_mtime); - cp[24] = 0; - /* Fix non-standard format. */ - if (cp[8] == '0') cp[8] = ' '; - (void) strcpy (vers_ts->ts_user, cp); - } -} - -#endif /* SERVER_SUPPORT */ -/* - * Gets the time-stamp for the file "file" and returns it in space it - * allocates - */ -char * -time_stamp (file) - const char *file; -{ - struct stat sb; - char *cp; - char *ts = NULL; - time_t mtime = 0L; - - if (!CVS_LSTAT (file, &sb)) - { - mtime = sb.st_mtime; - } - else if (! existence_error (errno)) - error (0, errno, "cannot lstat %s", file); - - /* If it's a symlink, return whichever is the newest mtime of - the link and its target, for safety. - */ - if (!CVS_STAT (file, &sb)) - { - if (mtime < sb.st_mtime) - mtime = sb.st_mtime; - } - else if (! existence_error (errno)) - error (0, errno, "cannot stat %s", file); - - if (mtime) - { - struct tm *tm_p; - ts = xmalloc (25); - /* We want to use the same timestamp format as is stored in the - st_mtime. For unix (and NT I think) this *must* be universal - time (UT), so that files don't appear to be modified merely - because the timezone has changed. For VMS, or hopefully other - systems where gmtime returns NULL, the modification time is - stored in local time, and therefore it is not possible to cause - st_mtime to be out of sync by changing the timezone. */ - tm_p = gmtime (&sb.st_mtime); - cp = tm_p ? asctime (tm_p) : ctime (&sb.st_mtime); - cp[24] = 0; - /* Fix non-standard format. */ - if (cp[8] == '0') cp[8] = ' '; - (void) strcpy (ts, cp); - } - - return (ts); -} - -/* - * free up a Vers_TS struct - */ -void -freevers_ts (versp) - Vers_TS **versp; -{ - if ((*versp)->srcfile) - freercsnode (&((*versp)->srcfile)); - if ((*versp)->vn_user) - free ((*versp)->vn_user); - if ((*versp)->vn_rcs) - free ((*versp)->vn_rcs); - if ((*versp)->vn_tag) - free ((*versp)->vn_tag); - if ((*versp)->ts_user) - free ((*versp)->ts_user); - if ((*versp)->ts_rcs) - free ((*versp)->ts_rcs); - if ((*versp)->options) - free ((*versp)->options); - if ((*versp)->tag) - free ((*versp)->tag); - if ((*versp)->date) - free ((*versp)->date); - if ((*versp)->ts_conflict) - free ((*versp)->ts_conflict); - free ((char *) *versp); - *versp = (Vers_TS *) NULL; -} diff --git a/contrib/cvs/src/version.c b/contrib/cvs/src/version.c deleted file mode 100644 index 09f99f4..0000000 --- a/contrib/cvs/src/version.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 1986-2005 The Free Software Foundation, Inc. - * - * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, - * and others. - * - * Portions Copyright (C) 1994 david d `zoo' zuhn - * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk - * Portions Copyright (C) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with this CVS source distribution. - * - * version.c - the CVS version number - */ - -#include "cvs.h" - -#ifdef CLIENT_SUPPORT -#ifdef SERVER_SUPPORT -char *config_string = " (client/server)\n"; -#else -char *config_string = " (client)\n"; -#endif -#else -#ifdef SERVER_SUPPORT -char *config_string = " (server)\n"; -#else -char *config_string = "\n"; -#endif -#endif - - - -static const char *const version_usage[] = -{ - "Usage: %s %s\n", - NULL -}; - - - -/* - * Output a version string for the client and server. - * - * This function will output the simple version number (for the '--version' - * option) or the version numbers of the client and server (using the 'version' - * command). - */ -int -version (argc, argv) - int argc; - char **argv; -{ - int err = 0; - - if (argc == -1) - usage (version_usage); - - if (current_parsed_root && current_parsed_root->isremote) - (void) fputs ("Client: ", stdout); - - /* 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 (PACKAGE_STRING, stdout); - (void) fputs (config_string, stdout); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root && current_parsed_root->isremote) - { - (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 deleted file mode 100644 index 0ef987c..0000000 --- a/contrib/cvs/src/watch.c +++ /dev/null @@ -1,522 +0,0 @@ -/* Implementation for "cvs watch add", "cvs watchers", and related commands - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -#include "cvs.h" -#include "edit.h" -#include "fileattr.h" -#include "watch.h" - -const char *const watch_usage[] = -{ - "Usage: %s %s {on|off|add|remove} [-lR] [-a <action>]... [<path>]...\n", - "on/off: Turn on/off read-only checkouts of files.\n", - "add/remove: Add or remove notification on actions.\n", - "-l (on/off/add/remove): Local directory only, not recursive.\n", - "-R (on/off/add/remove): Process directories recursively (default).\n", - "-a (add/remove): Specify what actions, one of: `edit', `unedit',\n", - " `commit', `all', or `none' (defaults to `all').\n", - "(Specify the --help global option for a list of other help options.)\n", - NULL -}; - -static struct addremove_args the_args; - -void -watch_modify_watchers (file, what) - const char *file; - struct addremove_args *what; -{ - char *curattr = fileattr_get0 (file, "_watchers"); - char *p; - char *pend; - char *nextp; - char *who; - int who_len; - char *mycurattr; - char *mynewattr; - size_t mynewattr_size; - - int add_edit_pending; - int add_unedit_pending; - int add_commit_pending; - int remove_edit_pending; - int remove_unedit_pending; - int remove_commit_pending; - int add_tedit_pending; - int add_tunedit_pending; - int add_tcommit_pending; - - who = getcaller (); - who_len = strlen (who); - - /* Look for current watcher types for this user. */ - mycurattr = NULL; - if (curattr != NULL) - { - p = curattr; - while (1) { - if (strncmp (who, p, who_len) == 0 - && p[who_len] == '>') - { - /* Found this user. */ - mycurattr = p + who_len + 1; - } - p = strchr (p, ','); - if (p == NULL) - break; - ++p; - } - } - if (mycurattr != NULL) - { - mycurattr = xstrdup (mycurattr); - p = strchr (mycurattr, ','); - if (p != NULL) - *p = '\0'; - } - - /* Now copy mycurattr to mynewattr, making the requisite modifications. - Note that we add a dummy '+' to the start of mynewattr, to reduce - special cases (but then we strip it off when we are done). */ - - mynewattr_size = sizeof "+edit+unedit+commit+tedit+tunedit+tcommit"; - if (mycurattr != NULL) - mynewattr_size += strlen (mycurattr); - mynewattr = xmalloc (mynewattr_size); - mynewattr[0] = '\0'; - - add_edit_pending = what->adding && what->edit; - add_unedit_pending = what->adding && what->unedit; - add_commit_pending = what->adding && what->commit; - remove_edit_pending = !what->adding && what->edit; - remove_unedit_pending = !what->adding && what->unedit; - remove_commit_pending = !what->adding && what->commit; - add_tedit_pending = what->add_tedit; - add_tunedit_pending = what->add_tunedit; - add_tcommit_pending = what->add_tcommit; - - /* Copy over existing watch types, except those to be removed. */ - p = mycurattr; - while (p != NULL) - { - pend = strchr (p, '+'); - if (pend == NULL) - { - pend = p + strlen (p); - nextp = NULL; - } - else - nextp = pend + 1; - - /* Process this item. */ - if (pend - p == 4 && strncmp ("edit", p, 4) == 0) - { - if (!remove_edit_pending) - strcat (mynewattr, "+edit"); - add_edit_pending = 0; - } - else if (pend - p == 6 && strncmp ("unedit", p, 6) == 0) - { - if (!remove_unedit_pending) - strcat (mynewattr, "+unedit"); - add_unedit_pending = 0; - } - else if (pend - p == 6 && strncmp ("commit", p, 6) == 0) - { - if (!remove_commit_pending) - strcat (mynewattr, "+commit"); - add_commit_pending = 0; - } - else if (pend - p == 5 && strncmp ("tedit", p, 5) == 0) - { - if (!what->remove_temp) - strcat (mynewattr, "+tedit"); - add_tedit_pending = 0; - } - else if (pend - p == 7 && strncmp ("tunedit", p, 7) == 0) - { - if (!what->remove_temp) - strcat (mynewattr, "+tunedit"); - add_tunedit_pending = 0; - } - else if (pend - p == 7 && strncmp ("tcommit", p, 7) == 0) - { - if (!what->remove_temp) - strcat (mynewattr, "+tcommit"); - add_tcommit_pending = 0; - } - else - { - char *mp; - - /* Copy over any unrecognized watch types, for future - expansion. */ - mp = mynewattr + strlen (mynewattr); - *mp++ = '+'; - strncpy (mp, p, pend - p); - *(mp + (pend - p)) = '\0'; - } - - /* Set up for next item. */ - p = nextp; - } - - /* Add in new watch types. */ - if (add_edit_pending) - strcat (mynewattr, "+edit"); - if (add_unedit_pending) - strcat (mynewattr, "+unedit"); - if (add_commit_pending) - strcat (mynewattr, "+commit"); - if (add_tedit_pending) - strcat (mynewattr, "+tedit"); - if (add_tunedit_pending) - strcat (mynewattr, "+tunedit"); - if (add_tcommit_pending) - strcat (mynewattr, "+tcommit"); - - { - char *curattr_new; - - curattr_new = - fileattr_modify (curattr, - who, - mynewattr[0] == '\0' ? NULL : mynewattr + 1, - '>', - ','); - /* If the attribute is unchanged, don't rewrite the attribute file. */ - if (!((curattr_new == NULL && curattr == NULL) - || (curattr_new != NULL - && curattr != NULL - && strcmp (curattr_new, curattr) == 0))) - fileattr_set (file, - "_watchers", - curattr_new); - if (curattr_new != NULL) - free (curattr_new); - } - - if (curattr != NULL) - free (curattr); - if (mycurattr != NULL) - free (mycurattr); - if (mynewattr != NULL) - free (mynewattr); -} - -static int addremove_fileproc PROTO ((void *callerdat, - struct file_info *finfo)); - -static int -addremove_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - watch_modify_watchers (finfo->file, &the_args); - return 0; -} - - - -static int addremove_filesdoneproc PROTO ((void *, int, const char *, - const char *, List *)); - -static int -addremove_filesdoneproc (callerdat, err, repository, update_dir, entries) - void *callerdat; - int err; - const char *repository; - const char *update_dir; - List *entries; -{ - if (the_args.setting_default) - watch_modify_watchers (NULL, &the_args); - return err; -} - -static int watch_addremove PROTO ((int argc, char **argv)); - -static int -watch_addremove (argc, argv) - int argc; - char **argv; -{ - int c; - int local = 0; - int err; - int a_omitted; - - a_omitted = 1; - the_args.commit = 0; - the_args.edit = 0; - the_args.unedit = 0; - optind = 0; - while ((c = getopt (argc, argv, "+lRa:")) != -1) - { - switch (c) - { - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'a': - a_omitted = 0; - if (strcmp (optarg, "edit") == 0) - the_args.edit = 1; - else if (strcmp (optarg, "unedit") == 0) - the_args.unedit = 1; - else if (strcmp (optarg, "commit") == 0) - the_args.commit = 1; - else if (strcmp (optarg, "all") == 0) - { - the_args.edit = 1; - the_args.unedit = 1; - the_args.commit = 1; - } - else if (strcmp (optarg, "none") == 0) - { - the_args.edit = 0; - the_args.unedit = 0; - the_args.commit = 0; - } - else - usage (watch_usage); - break; - case '?': - default: - usage (watch_usage); - break; - } - } - argc -= optind; - argv += optind; - - if (a_omitted) - { - the_args.edit = 1; - the_args.unedit = 1; - the_args.commit = 1; - } - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - start_server (); - ign_setup (); - - if (local) - send_arg ("-l"); - /* FIXME: copes poorly with "all" if server is extended to have - new watch types and client is still running an old version. */ - if (the_args.edit) - option_with_arg ("-a", "edit"); - if (the_args.unedit) - option_with_arg ("-a", "unedit"); - if (the_args.commit) - option_with_arg ("-a", "commit"); - if (!the_args.edit && !the_args.unedit && !the_args.commit) - option_with_arg ("-a", "none"); - send_arg ("--"); - send_files (argc, argv, local, 0, SEND_NO_CONTENTS); - send_file_names (argc, argv, SEND_EXPAND_WILD); - send_to_server (the_args.adding ? - "watch-add\012" : "watch-remove\012", - 0); - return get_responses_and_close (); - } -#endif /* CLIENT_SUPPORT */ - - the_args.setting_default = (argc <= 0); - - lock_tree_for_write (argc, argv, local, W_LOCAL, 0); - - err = start_recursion (addremove_fileproc, addremove_filesdoneproc, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc, argv, local, W_LOCAL, 0, CVS_LOCK_NONE, - (char *) NULL, 1, (char *) NULL); - - Lock_Cleanup (); - return err; -} - -int -watch_add (argc, argv) - int argc; - char **argv; -{ - the_args.adding = 1; - return watch_addremove (argc, argv); -} - -int -watch_remove (argc, argv) - int argc; - char **argv; -{ - the_args.adding = 0; - return watch_addremove (argc, argv); -} - -int -watch (argc, argv) - int argc; - char **argv; -{ - if (argc <= 1) - usage (watch_usage); - if (strcmp (argv[1], "on") == 0) - { - --argc; - ++argv; - return watch_on (argc, argv); - } - else if (strcmp (argv[1], "off") == 0) - { - --argc; - ++argv; - return watch_off (argc, argv); - } - else if (strcmp (argv[1], "add") == 0) - { - --argc; - ++argv; - return watch_add (argc, argv); - } - else if (strcmp (argv[1], "remove") == 0) - { - --argc; - ++argv; - return watch_remove (argc, argv); - } - else - usage (watch_usage); - return 0; -} - -static const char *const watchers_usage[] = -{ - "Usage: %s %s [-lR] [<file>]...\n", - "-l\tProcess this directory only (not recursive).\n", - "-R\tProcess directories recursively (default).\n", - "(Specify the --help global option for a list of other help options.)\n", - NULL -}; - -static int watchers_fileproc PROTO ((void *callerdat, - struct file_info *finfo)); - -static int -watchers_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - char *them; - char *p; - - them = fileattr_get0 (finfo->file, "_watchers"); - if (them == NULL) - return 0; - - cvs_output (finfo->fullname, 0); - - p = them; - while (1) - { - cvs_output ("\t", 1); - while (*p != '>' && *p != '\0') - cvs_output (p++, 1); - if (*p == '\0') - { - /* Only happens if attribute is misformed. */ - cvs_output ("\n", 1); - break; - } - ++p; - cvs_output ("\t", 1); - while (1) - { - while (*p != '+' && *p != ',' && *p != '\0') - cvs_output (p++, 1); - if (*p == '\0') - { - cvs_output ("\n", 1); - goto out; - } - if (*p == ',') - { - ++p; - break; - } - ++p; - cvs_output ("\t", 1); - } - cvs_output ("\n", 1); - } - out:; - free (them); - return 0; -} - -int -watchers (argc, argv) - int argc; - char **argv; -{ - int local = 0; - int c; - - if (argc == -1) - usage (watchers_usage); - - optind = 0; - while ((c = getopt (argc, argv, "+lR")) != -1) - { - switch (c) - { - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case '?': - default: - usage (watchers_usage); - break; - } - } - argc -= optind; - argv += optind; - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) - { - start_server (); - ign_setup (); - - if (local) - send_arg ("-l"); - send_arg ("--"); - send_files (argc, argv, local, 0, SEND_NO_CONTENTS); - send_file_names (argc, argv, SEND_EXPAND_WILD); - send_to_server ("watchers\012", 0); - return get_responses_and_close (); - } -#endif /* CLIENT_SUPPORT */ - - return start_recursion (watchers_fileproc, (FILESDONEPROC) NULL, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc, argv, local, W_LOCAL, 0, CVS_LOCK_READ, - (char *) NULL, 1, (char *) NULL); -} diff --git a/contrib/cvs/src/watch.h b/contrib/cvs/src/watch.h deleted file mode 100644 index 0394635..0000000 --- a/contrib/cvs/src/watch.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Interface to "cvs watch add", "cvs watchers", and related features - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -extern const char *const watch_usage[]; - -/* Flags to pass between the various functions making up the - add/remove code. All in a single structure in case there is some - need to make the code reentrant some day. */ - -struct addremove_args { - /* A flag for each watcher type. */ - int edit; - int unedit; - int commit; - - /* Are we adding or removing (non-temporary) edit,unedit,and/or commit - watches? */ - int adding; - - /* Should we add a temporary edit watch? */ - int add_tedit; - /* Should we add a temporary unedit watch? */ - int add_tunedit; - /* Should we add a temporary commit watch? */ - int add_tcommit; - - /* Should we remove all temporary watches? */ - int remove_temp; - - /* Should we set the default? This is here for passing among various - routines in watch.c (a good place for it if there is ever any reason - to make the stuff reentrant), not for watch_modify_watchers. */ - int setting_default; -}; - -/* Modify the watchers for FILE. *WHAT tells what to do to them. - If FILE is NULL, modify default args (WHAT->SETTING_DEFAULT is - not used). */ -extern void watch_modify_watchers PROTO ((const char *file, - struct addremove_args *what)); - -extern int watch_add PROTO ((int argc, char **argv)); -extern int watch_remove PROTO ((int argc, char **argv)); diff --git a/contrib/cvs/src/wrapper.c b/contrib/cvs/src/wrapper.c deleted file mode 100644 index 512e96c..0000000 --- a/contrib/cvs/src/wrapper.c +++ /dev/null @@ -1,623 +0,0 @@ -/* This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -#include "cvs.h" -#include "getline.h" - -/* - Original Author: athan@morgan.com <Andrew C. Athan> 2/1/94 - Modified By: vdemarco@bou.shl.com - - This package was written to support the NEXTSTEP concept of - "wrappers." These are essentially directories that are to be - treated as "files." This package allows such wrappers to be - "processed" on the way in and out of CVS. The intended use is to - wrap up a wrapper into a single tar, such that that tar can be - treated as a single binary file in CVS. To solve the problem - effectively, it was also necessary to be able to prevent rcsmerge - application at appropriate times. - - ------------------ - Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers) - - wildcard [option value][option value]... - - where option is one of - -m update methodology value: MERGE or COPY - -k default -k rcs option to use on import or add - - and value is a single-quote delimited value. - - E.g: - *.nib -f 'gunzipuntar' -t 'targzip' -m 'COPY' -*/ - - -typedef struct { - char *wildCard; - char *tocvsFilter; - char *fromcvsFilter; - char *rcsOption; - WrapMergeMethod mergeMethod; -} WrapperEntry; - -static WrapperEntry **wrap_list=NULL; -static WrapperEntry **wrap_saved_list=NULL; - -static int wrap_size=0; -static int wrap_count=0; -static int wrap_tempcount=0; - -/* FIXME: the relationship between wrap_count, wrap_tempcount, - * wrap_saved_count, and wrap_saved_tempcount is not entirely clear; - * it is certainly suspicious that wrap_saved_count is never set to a - * value other than zero! If the variable isn't being used, it should - * be removed. And in general, we should describe how temporary - * vs. permanent wrappers are implemented, and then make sure the - * implementation is actually doing that. - * - * Right now things seem to be working, but that's no guarantee there - * isn't a bug lurking somewhere in the murk. - */ - -static int wrap_saved_count=0; - -static int wrap_saved_tempcount=0; - -#define WRAPPER_GROW 8 - -void wrap_add_entry PROTO((WrapperEntry *e,int temp)); -void wrap_kill PROTO((void)); -void wrap_kill_temp PROTO((void)); -void wrap_free_entry PROTO((WrapperEntry *e)); -void wrap_free_entry_internal PROTO((WrapperEntry *e)); -void wrap_restore_saved PROTO((void)); - -void wrap_setup() -{ - /* FIXME-reentrancy: if we do a multithreaded server, will need to - move this to a per-connection data structure, or better yet - think about a cleaner solution. */ - static int wrap_setup_already_done = 0; - char *homedir; - - if (wrap_setup_already_done != 0) - return; - else - wrap_setup_already_done = 1; - - if (!current_parsed_root->isremote) - { - char *file; - - file = xmalloc (strlen (current_parsed_root->directory) - + sizeof (CVSROOTADM) - + sizeof (CVSROOTADM_WRAPPER) - + 3); - /* Then add entries found in repository, if it exists. */ - (void) sprintf (file, "%s/%s/%s", current_parsed_root->directory, CVSROOTADM, - CVSROOTADM_WRAPPER); - if (isfile (file)) - { - wrap_add_file(file,0); - } - free (file); - } - - /* Then add entries found in home dir, (if user has one) and file - exists. */ - homedir = get_homedir (); - /* If we can't find a home directory, ignore ~/.cvswrappers. This may - make tracking down problems a bit of a pain, but on the other - hand it might be obnoxious to complain when CVS will function - just fine without .cvswrappers (and many users won't even know what - .cvswrappers is). */ - if (homedir != NULL) - { - char *file = strcat_filename_onto_homedir (homedir, CVSDOTWRAPPER); - if (isfile (file)) - { - wrap_add_file (file, 0); - } - free (file); - } - - /* FIXME: calling wrap_add() below implies that the CVSWRAPPERS - * environment variable contains exactly one "wrapper" -- a line - * of the form - * - * FILENAME_PATTERN FLAG OPTS [ FLAG OPTS ...] - * - * This may disagree with the documentation, which states: - * - * `$CVSWRAPPERS' - * A whitespace-separated list of file name patterns that CVS - * should treat as wrappers. *Note Wrappers::. - * - * Does this mean the environment variable can hold multiple - * wrappers lines? If so, a single call to wrap_add() is - * insufficient. - */ - - /* Then add entries found in CVSWRAPPERS environment variable. */ - wrap_add (getenv (WRAPPER_ENV), 0); -} - -#ifdef CLIENT_SUPPORT -/* Send -W arguments for the wrappers to the server. The command must - be one that accepts them (e.g. update, import). */ -void -wrap_send () -{ - int i; - - for (i = 0; i < wrap_count + wrap_tempcount; ++i) - { - if (wrap_list[i]->tocvsFilter != NULL - || wrap_list[i]->fromcvsFilter != NULL) - /* For greater studliness we would print the offending option - and (more importantly) where we found it. */ - error (0, 0, "\ --t and -f wrapper options are not supported remotely; ignored"); - if (wrap_list[i]->mergeMethod == WRAP_COPY) - /* For greater studliness we would print the offending option - and (more importantly) where we found it. */ - error (0, 0, "\ --m wrapper option is not supported remotely; ignored"); - send_to_server ("Argument -W\012Argument ", 0); - send_to_server (wrap_list[i]->wildCard, 0); - send_to_server (" -k '", 0); - if (wrap_list[i]->rcsOption != NULL) - send_to_server (wrap_list[i]->rcsOption, 0); - else - send_to_server ("kv", 0); - send_to_server ("'\012", 0); - } -} -#endif /* CLIENT_SUPPORT */ - -#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) -/* Output wrapper entries in the format of cvswrappers lines. - * - * This is useful when one side of a client/server connection wants to - * send its wrappers to the other; since the receiving side would like - * to use wrap_add() to incorporate the wrapper, it's best if the - * entry arrives in this format. - * - * The entries are stored in `line', which is allocated here. Caller - * can free() it. - * - * If first_call_p is nonzero, then start afresh. */ -void -wrap_unparse_rcs_options (line, first_call_p) - char **line; - int first_call_p; -{ - /* FIXME-reentrancy: we should design a reentrant interface, like - a callback which gets handed each wrapper (a multithreaded - server being the most concrete reason for this, but the - non-reentrant interface is fairly unnecessary/ugly). */ - static int i; - - if (first_call_p) - i = 0; - - if (i >= wrap_count + wrap_tempcount) { - *line = NULL; - return; - } - - *line = xmalloc (strlen (wrap_list[i]->wildCard) - + strlen ("\t") - + strlen (" -k '") - + (wrap_list[i]->rcsOption != NULL ? - strlen (wrap_list[i]->rcsOption) : 2) - + strlen ("'") - + 1); /* leave room for '\0' */ - - strcpy (*line, wrap_list[i]->wildCard); - strcat (*line, " -k '"); - if (wrap_list[i]->rcsOption != NULL) - strcat (*line, wrap_list[i]->rcsOption); - else - strcat (*line, "kv"); - strcat (*line, "'"); - - ++i; -} -#endif /* SERVER_SUPPORT || CLIENT_SUPPORT */ - -/* - * Remove fmt str specifier other than %% or %s. And allow - * only max_s %s specifiers - */ -void -wrap_clean_fmt_str(char *fmt, int max_s) -{ - while (*fmt) { - if (fmt[0] == '%' && fmt[1]) - { - if (fmt[1] == '%') - fmt++; - else - if (fmt[1] == 's' && max_s > 0) - { - max_s--; - fmt++; - } else - *fmt = ' '; - } - fmt++; - } -} - -/* - * Open a file and read lines, feeding each line to a line parser. Arrange - * for keeping a temporary list of wrappers at the end, if the "temp" - * argument is set. - */ -void -wrap_add_file (file, temp) - const char *file; - int temp; -{ - FILE *fp; - char *line = NULL; - size_t line_allocated = 0; - - wrap_restore_saved (); - wrap_kill_temp (); - - /* Load the file. */ - fp = CVS_FOPEN (file, "r"); - if (fp == NULL) - { - if (!existence_error (errno)) - error (0, errno, "cannot open %s", file); - return; - } - while (getline (&line, &line_allocated, fp) >= 0) - wrap_add (line, temp); - if (line) - free (line); - if (ferror (fp)) - error (0, errno, "cannot read %s", file); - if (fclose (fp) == EOF) - error (0, errno, "cannot close %s", file); -} - -void -wrap_kill() -{ - wrap_kill_temp(); - while(wrap_count) - wrap_free_entry(wrap_list[--wrap_count]); -} - -void -wrap_kill_temp() -{ - WrapperEntry **temps=wrap_list+wrap_count; - - while(wrap_tempcount) - wrap_free_entry(temps[--wrap_tempcount]); -} - -void -wrap_free_entry(e) - WrapperEntry *e; -{ - wrap_free_entry_internal(e); - free(e); -} - -void -wrap_free_entry_internal(e) - WrapperEntry *e; -{ - free (e->wildCard); - if (e->tocvsFilter) - free (e->tocvsFilter); - if (e->fromcvsFilter) - free (e->fromcvsFilter); - if (e->rcsOption) - free (e->rcsOption); -} - -void -wrap_restore_saved() -{ - if(!wrap_saved_list) - return; - - wrap_kill(); - - free(wrap_list); - - wrap_list=wrap_saved_list; - wrap_count=wrap_saved_count; - wrap_tempcount=wrap_saved_tempcount; - - wrap_saved_list=NULL; - wrap_saved_count=0; - wrap_saved_tempcount=0; -} - -void -wrap_add (line, isTemp) - char *line; - int isTemp; -{ - char *temp; - char ctemp; - WrapperEntry e; - char opt; - - if (!line || line[0] == '#') - return; - - memset (&e, 0, sizeof(e)); - - /* Search for the wild card */ - while (*line && isspace ((unsigned char) *line)) - ++line; - for (temp = line; - *line && !isspace ((unsigned char) *line); - ++line) - ; - if(temp==line) - return; - - ctemp=*line; - *line='\0'; - - e.wildCard=xstrdup(temp); - *line=ctemp; - - while(*line){ - /* Search for the option */ - while(*line && *line!='-') - ++line; - if(!*line) - break; - ++line; - if(!*line) - break; - opt=*line; - - /* Search for the filter commandline */ - for(++line;*line && *line!='\'';++line); - if(!*line) - break; - - for(temp=++line;*line && (*line!='\'' || line[-1]=='\\');++line) - ; - - /* This used to "break;" (ignore the option) if there was a - single character between the single quotes (I'm guessing - that was accidental). Now it "break;"s if there are no - characters. I'm not sure either behavior is particularly - necessary--the current options might not require '' - arguments, but surely some future option legitimately - might. Also I'm not sure that ignoring the option is a - swift way to handle syntax errors in general. */ - if (line==temp) - break; - - ctemp=*line; - *line='\0'; - switch(opt){ - case 'f': - /* Before this is reenabled, need to address the problem in - commit.c (see - http://ximbiot.com/cvs/cvshome/docs/infowrapper.html). */ - error (1, 0, - "-t/-f wrappers not supported by this version of CVS"); - - if(e.fromcvsFilter) - free(e.fromcvsFilter); - /* FIXME: error message should say where the bad value - came from. */ - e.fromcvsFilter=expand_path (temp, "<wrapper>", 0); - if (!e.fromcvsFilter) - error (1, 0, "Correct above errors first"); - break; - case 't': - /* Before this is reenabled, need to address the problem in - commit.c (see - http://ximbiot.com/cvs/cvshome/docs/infowrapper.html). */ - error (1, 0, - "-t/-f wrappers not supported by this version of CVS"); - - if(e.tocvsFilter) - free(e.tocvsFilter); - /* FIXME: error message should say where the bad value - came from. */ - e.tocvsFilter=expand_path (temp, "<wrapper>", 0); - if (!e.tocvsFilter) - error (1, 0, "Correct above errors first"); - break; - case 'm': - if(*temp=='C' || *temp=='c') - e.mergeMethod=WRAP_COPY; - else - e.mergeMethod=WRAP_MERGE; - break; - case 'k': - if (e.rcsOption) - free (e.rcsOption); - e.rcsOption = strcmp (temp, "kv") ? xstrdup (temp) : NULL; - break; - default: - break; - } - *line=ctemp; - if(!*line)break; - ++line; - } - - wrap_add_entry(&e, isTemp); -} - -void -wrap_add_entry(e, temp) - WrapperEntry *e; - int temp; -{ - int x; - if(wrap_count+wrap_tempcount>=wrap_size){ - wrap_size += WRAPPER_GROW; - wrap_list = (WrapperEntry **) xrealloc ((char *) wrap_list, - wrap_size * - sizeof (WrapperEntry *)); - } - - if(!temp && wrap_tempcount){ - for(x=wrap_count+wrap_tempcount-1;x>=wrap_count;--x) - wrap_list[x+1]=wrap_list[x]; - } - - x=(temp ? wrap_count+(wrap_tempcount++):(wrap_count++)); - wrap_list[x]=(WrapperEntry *)xmalloc(sizeof(WrapperEntry)); - *wrap_list[x]=*e; -} - -/* Return 1 if the given filename is a wrapper filename */ -int -wrap_name_has (name,has) - const char *name; - WrapMergeHas has; -{ - int x,count=wrap_count+wrap_tempcount; - char *temp; - - for(x=0;x<count;++x) - if (CVS_FNMATCH (wrap_list[x]->wildCard, name, 0) == 0){ - switch(has){ - case WRAP_TOCVS: - temp=wrap_list[x]->tocvsFilter; - break; - case WRAP_FROMCVS: - temp=wrap_list[x]->fromcvsFilter; - break; - case WRAP_RCSOPTION: - temp = wrap_list[x]->rcsOption; - break; - default: - abort (); - } - if(temp==NULL) - return (0); - else - return (1); - } - return (0); -} - -static WrapperEntry *wrap_matching_entry PROTO ((const char *)); - -static WrapperEntry * -wrap_matching_entry (name) - const char *name; -{ - int x,count=wrap_count+wrap_tempcount; - - for(x=0;x<count;++x) - if (CVS_FNMATCH (wrap_list[x]->wildCard, name, 0) == 0) - return wrap_list[x]; - return (WrapperEntry *)NULL; -} - -/* Return the RCS options for FILENAME in a newly malloc'd string. If - ASFLAG, then include "-k" at the beginning (e.g. "-kb"), otherwise - just give the option itself (e.g. "b"). */ -char * -wrap_rcsoption (filename, asflag) - const char *filename; - int asflag; -{ - WrapperEntry *e = wrap_matching_entry (filename); - char *buf; - - if (e == NULL || e->rcsOption == NULL || (*e->rcsOption == '\0')) - return NULL; - - buf = xmalloc (strlen (e->rcsOption) + 3); - if (asflag) - { - strcpy (buf, "-k"); - strcat (buf, e->rcsOption); - } - else - { - strcpy (buf, e->rcsOption); - } - return buf; -} - -char * -wrap_tocvs_process_file(fileName) - const char *fileName; -{ - WrapperEntry *e=wrap_matching_entry(fileName); - static char *buf = NULL; - char *args; - - if(e==NULL || e->tocvsFilter==NULL) - return NULL; - - if (buf != NULL) - free (buf); - buf = cvs_temp_name (); - - args = xmalloc (strlen (e->tocvsFilter) - + strlen (fileName) - + strlen (buf)); - - wrap_clean_fmt_str(e->tocvsFilter, 2); - sprintf (args, e->tocvsFilter, fileName, buf); - run_setup (args); - run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY ); - free (args); - - return buf; -} - -int -wrap_merge_is_copy (fileName) - const char *fileName; -{ - WrapperEntry *e=wrap_matching_entry(fileName); - if(e==NULL || e->mergeMethod==WRAP_MERGE) - return 0; - - return 1; -} - -void -wrap_fromcvs_process_file(fileName) - const char *fileName; -{ - char *args; - WrapperEntry *e=wrap_matching_entry(fileName); - - if(e==NULL || e->fromcvsFilter==NULL) - return; - - args = xmalloc (strlen (e->fromcvsFilter) - + strlen (fileName)); - - wrap_clean_fmt_str(e->fromcvsFilter, 1); - sprintf (args, e->fromcvsFilter, fileName); - run_setup (args); - run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL ); - free (args); - return; -} diff --git a/contrib/cvs/src/zlib.c b/contrib/cvs/src/zlib.c deleted file mode 100644 index 46ed0e6..0000000 --- a/contrib/cvs/src/zlib.c +++ /dev/null @@ -1,760 +0,0 @@ -/* zlib.c --- interface to the zlib compression library - Ian Lance Taylor <ian@cygnus.com> - - This file is part of GNU CVS. - - GNU CVS is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ - -/* The routines in this file are the interface between the CVS - client/server support and the zlib compression library. */ - -#include <assert.h> -#include "cvs.h" -#include "buffer.h" - -#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) - -#include "zlib.h" - -/* OS/2 doesn't have EIO. FIXME: this whole notion of turning - a different error into EIO strikes me as pretty dubious. */ -#if !defined (EIO) -#define EIO EBADPOS -#endif - -/* The compression interface is built upon the buffer data structure. - We provide a buffer type which compresses or decompresses the data - which passes through it. An input buffer decompresses the data - read from an underlying buffer, and an output buffer compresses the - data before writing it to an underlying buffer. */ - -/* This structure is the closure field of the buffer. */ - -struct compress_buffer -{ - /* The underlying buffer. */ - struct buffer *buf; - /* The compression information. */ - z_stream zstr; -}; - -static void compress_error PROTO((int, int, z_stream *, const char *)); -static int compress_buffer_input PROTO((void *, char *, int, int, int *)); -static int compress_buffer_output PROTO((void *, const char *, int, int *)); -static int compress_buffer_flush PROTO((void *)); -static int compress_buffer_block PROTO((void *, int)); -static int compress_buffer_shutdown_input PROTO((struct buffer *)); -static int compress_buffer_shutdown_output PROTO((struct buffer *)); - -/* Report an error from one of the zlib functions. */ - -static void -compress_error (status, zstatus, zstr, msg) - int status; - int zstatus; - z_stream *zstr; - const char *msg; -{ - int hold_errno; - const char *zmsg; - char buf[100]; - - hold_errno = errno; - - zmsg = zstr->msg; - if (zmsg == NULL) - { - sprintf (buf, "error %d", zstatus); - zmsg = buf; - } - - error (status, - zstatus == Z_ERRNO ? hold_errno : 0, - "%s: %s", msg, zmsg); -} - -/* Create a compression buffer. */ - -struct buffer * -compress_buffer_initialize (buf, input, level, memory) - struct buffer *buf; - int input; - int level; - void (*memory) PROTO((struct buffer *)); -{ - struct compress_buffer *n; - int zstatus; - - n = (struct compress_buffer *) xmalloc (sizeof *n); - memset (n, 0, sizeof *n); - - n->buf = buf; - - if (input) - zstatus = inflateInit (&n->zstr); - else - zstatus = deflateInit (&n->zstr, level); - if (zstatus != Z_OK) - compress_error (1, zstatus, &n->zstr, "compression initialization"); - - /* There may already be data buffered on BUF. For an output - buffer, this is OK, because these routines will just use the - buffer routines to append data to the (uncompressed) data - already on BUF. An input buffer expects to handle a single - buffer_data of buffered input to be uncompressed, so that is OK - provided there is only one buffer. At present that is all - there ever will be; if this changes, compress_buffer_input must - be modified to handle multiple input buffers. */ - assert (! input || buf->data == NULL || buf->data->next == NULL); - - return buf_initialize (input ? compress_buffer_input : NULL, - input ? NULL : compress_buffer_output, - input ? NULL : compress_buffer_flush, - compress_buffer_block, - (input - ? compress_buffer_shutdown_input - : compress_buffer_shutdown_output), - memory, - n); -} - -/* Input data from a compression buffer. */ - -static int -compress_buffer_input (closure, data, need, size, got) - void *closure; - char *data; - int need; - int size; - int *got; -{ - struct compress_buffer *cb = (struct compress_buffer *) closure; - struct buffer_data *bd; - - if (cb->buf->input == NULL) - abort (); - - /* We use a single buffer_data structure to buffer up data which - the z_stream structure won't use yet. We can safely store this - on cb->buf->data, because we never call the buffer routines on - cb->buf; we only call the buffer input routine, since that - gives us the semantics we want. As noted in - compress_buffer_initialize, the buffer_data structure may - already exist, and hold data which was already read and - buffered before the decompression began. */ - bd = cb->buf->data; - if (bd == NULL) - { - bd = ((struct buffer_data *) xmalloc (sizeof (struct buffer_data))); - if (bd == NULL) - return -2; - bd->text = (char *) xmalloc (BUFFER_DATA_SIZE); - if (bd->text == NULL) - { - free (bd); - return -2; - } - bd->bufp = bd->text; - bd->size = 0; - cb->buf->data = bd; - } - - cb->zstr.avail_out = size; - cb->zstr.next_out = (Bytef *) data; - - while (1) - { - int zstatus, sofar, status, nread; - - /* First try to inflate any data we already have buffered up. - This is useful even if we don't have any buffered data, - because there may be data buffered inside the z_stream - structure. */ - - cb->zstr.avail_in = bd->size; - cb->zstr.next_in = (Bytef *) bd->bufp; - - do - { - zstatus = inflate (&cb->zstr, Z_NO_FLUSH); - if (zstatus == Z_STREAM_END) - break; - if (zstatus != Z_OK && zstatus != Z_BUF_ERROR) - { - compress_error (0, zstatus, &cb->zstr, "inflate"); - return EIO; - } - } while (cb->zstr.avail_in > 0 - && cb->zstr.avail_out > 0); - - bd->size = cb->zstr.avail_in; - bd->bufp = (char *) cb->zstr.next_in; - - if (zstatus == Z_STREAM_END) - return -1; - - /* If we have obtained NEED bytes, then return, unless NEED is - zero and we haven't obtained anything at all. If NEED is - zero, we will keep reading from the underlying buffer until - we either can't read anything, or we have managed to - inflate at least one byte. */ - sofar = size - cb->zstr.avail_out; - if (sofar > 0 && sofar >= need) - break; - - /* All our buffered data should have been processed at this - point. */ - assert (bd->size == 0); - - /* This will work well in the server, because this call will - do an unblocked read and fetch all the available data. In - the client, this will read a single byte from the stdio - stream, which will cause us to call inflate once per byte. - It would be more efficient if we could make a call which - would fetch all the available bytes, and at least one byte. */ - - status = (*cb->buf->input) (cb->buf->closure, bd->text, - need > 0 ? 1 : 0, - BUFFER_DATA_SIZE, &nread); - if (status != 0) - return status; - - /* If we didn't read anything, then presumably the buffer is - in nonblocking mode, and we should just get out now with - whatever we've inflated. */ - if (nread == 0) - { - assert (need == 0); - break; - } - - bd->bufp = bd->text; - bd->size = nread; - } - - *got = size - cb->zstr.avail_out; - - return 0; -} - -/* Output data to a compression buffer. */ - -static int -compress_buffer_output (closure, data, have, wrote) - void *closure; - const char *data; - int have; - int *wrote; -{ - struct compress_buffer *cb = (struct compress_buffer *) closure; - - cb->zstr.avail_in = have; - cb->zstr.next_in = (unsigned char *) data; - - while (cb->zstr.avail_in > 0) - { - char buffer[BUFFER_DATA_SIZE]; - int zstatus; - - cb->zstr.avail_out = BUFFER_DATA_SIZE; - cb->zstr.next_out = (unsigned char *) buffer; - - zstatus = deflate (&cb->zstr, Z_NO_FLUSH); - if (zstatus != Z_OK) - { - compress_error (0, zstatus, &cb->zstr, "deflate"); - return EIO; - } - - if (cb->zstr.avail_out != BUFFER_DATA_SIZE) - buf_output (cb->buf, buffer, - BUFFER_DATA_SIZE - cb->zstr.avail_out); - } - - *wrote = have; - - /* We will only be here because buf_send_output was called on the - compression buffer. That means that we should now call - buf_send_output on the underlying buffer. */ - return buf_send_output (cb->buf); -} - -/* Flush a compression buffer. */ - -static int -compress_buffer_flush (closure) - void *closure; -{ - struct compress_buffer *cb = (struct compress_buffer *) closure; - - cb->zstr.avail_in = 0; - cb->zstr.next_in = NULL; - - while (1) - { - char buffer[BUFFER_DATA_SIZE]; - int zstatus; - - cb->zstr.avail_out = BUFFER_DATA_SIZE; - cb->zstr.next_out = (unsigned char *) buffer; - - zstatus = deflate (&cb->zstr, Z_SYNC_FLUSH); - - /* The deflate function will return Z_BUF_ERROR if it can't do - anything, which in this case means that all data has been - flushed. */ - if (zstatus == Z_BUF_ERROR) - break; - - if (zstatus != Z_OK) - { - compress_error (0, zstatus, &cb->zstr, "deflate flush"); - return EIO; - } - - if (cb->zstr.avail_out != BUFFER_DATA_SIZE) - buf_output (cb->buf, buffer, - BUFFER_DATA_SIZE - cb->zstr.avail_out); - - /* If the deflate function did not fill the output buffer, - then all data has been flushed. */ - if (cb->zstr.avail_out > 0) - break; - } - - /* Now flush the underlying buffer. Note that if the original - call to buf_flush passed 1 for the BLOCK argument, then the - buffer will already have been set into blocking mode, so we - should always pass 0 here. */ - return buf_flush (cb->buf, 0); -} - -/* The block routine for a compression buffer. */ - -static int -compress_buffer_block (closure, block) - void *closure; - int block; -{ - struct compress_buffer *cb = (struct compress_buffer *) closure; - - if (block) - return set_block (cb->buf); - else - return set_nonblock (cb->buf); -} - -/* Shut down an input buffer. */ - -static int -compress_buffer_shutdown_input (buf) - struct buffer *buf; -{ - struct compress_buffer *cb = (struct compress_buffer *) buf->closure; - int zstatus; - - /* Don't make any attempt to pick up trailing data since we are shutting - * down. If the client doesn't know we are shutting down, we might not - * see the EOF we are expecting. - */ - - zstatus = inflateEnd (&cb->zstr); - if (zstatus != Z_OK) - { - compress_error (0, zstatus, &cb->zstr, "inflateEnd"); - return EIO; - } - - return buf_shutdown (cb->buf); -} - -/* Shut down an output buffer. */ - -static int -compress_buffer_shutdown_output (buf) - struct buffer *buf; -{ - struct compress_buffer *cb = (struct compress_buffer *) buf->closure; - int zstatus, status; - - do - { - char buffer[BUFFER_DATA_SIZE]; - - cb->zstr.avail_out = BUFFER_DATA_SIZE; - cb->zstr.next_out = (unsigned char *) buffer; - - zstatus = deflate (&cb->zstr, Z_FINISH); - if (zstatus != Z_OK && zstatus != Z_STREAM_END) - { - compress_error (0, zstatus, &cb->zstr, "deflate finish"); - return EIO; - } - - if (cb->zstr.avail_out != BUFFER_DATA_SIZE) - buf_output (cb->buf, buffer, - BUFFER_DATA_SIZE - cb->zstr.avail_out); - } while (zstatus != Z_STREAM_END); - - zstatus = deflateEnd (&cb->zstr); - if (zstatus != Z_OK) - { - compress_error (0, zstatus, &cb->zstr, "deflateEnd"); - return EIO; - } - - status = buf_flush (cb->buf, 1); - if (status != 0) - return status; - - return buf_shutdown (cb->buf); -} - - - -/* Here is our librarified gzip implementation. It is very minimal - but attempts to be RFC1952 compliant. */ - -/* GZIP ID byte values */ -#define GZIP_ID1 31 -#define GZIP_ID2 139 - -/* Compression methods */ -#define GZIP_CDEFLATE 8 - -/* Flags */ -#define GZIP_FTEXT 1 -#define GZIP_FHCRC 2 -#define GZIP_FEXTRA 4 -#define GZIP_FNAME 8 -#define GZIP_FCOMMENT 16 - -/* BUF should contain SIZE bytes of gzipped data (RFC1952/RFC1951). - We are to uncompress the data and write the result to the file - descriptor FD. If something goes wrong, give a nonfatal error message - mentioning FULLNAME as the name of the file for FD. Return 1 if - it is an error we can't recover from. */ - -int -gunzip_and_write (fd, fullname, buf, size) - int fd; - char *fullname; - unsigned char *buf; - size_t size; -{ - size_t pos; - z_stream zstr; - int zstatus; - unsigned char outbuf[32768]; - unsigned long crc; - - if (size < 10) - { - error (0, 0, "gzipped data too small - lacks complete header"); - return 1; - } - if (buf[0] != GZIP_ID1 || buf[1] != GZIP_ID2) - { - error (0, 0, "gzipped data does not start with gzip identification"); - return 1; - } - if (buf[2] != GZIP_CDEFLATE) - { - error (0, 0, "only the deflate compression method is supported"); - return 1; - } - - /* Skip over the fixed header, and then skip any of the variable-length - fields. As we skip each field, we keep pos <= size. The checks - on positions and lengths are really checks for malformed or - incomplete gzip data. */ - pos = 10; - if (buf[3] & GZIP_FEXTRA) - { - if (pos + 2 >= size) - { - error (0, 0, "%s lacks proper gzip XLEN field", fullname); - return 1; - } - pos += buf[pos] + (buf[pos + 1] << 8) + 2; - if (pos > size) - { - error (0, 0, "%s lacks proper gzip \"extra field\"", fullname); - return 1; - } - - } - if (buf[3] & GZIP_FNAME) - { - unsigned char *p = memchr(buf + pos, '\0', size - pos); - if (p == NULL) - { - error (0, 0, "%s has bad gzip filename field", fullname); - return 1; - } - pos = p - buf + 1; - } - if (buf[3] & GZIP_FCOMMENT) - { - unsigned char *p = memchr(buf + pos, '\0', size - pos); - if (p == NULL) - { - error (0, 0, "%s has bad gzip comment field", fullname); - return 1; - } - pos = p - buf + 1; - } - if (buf[3] & GZIP_FHCRC) - { - pos += 2; - if (pos > size) - { - error (0, 0, "%s has bad gzip CRC16 field", fullname); - return 1; - } - } - - /* There could be no data to decompress - check and short circuit. */ - if (pos >= size) - { - error (0, 0, "gzip data incomplete for %s (no data)", fullname); - return 1; - } - - memset (&zstr, 0, sizeof zstr); - /* Passing a negative argument tells zlib not to look for a zlib - (RFC1950) header. This is an undocumented feature; I suppose if - we wanted to be anal we could synthesize a header instead, - but why bother? */ - zstatus = inflateInit2 (&zstr, -15); - - if (zstatus != Z_OK) - compress_error (1, zstatus, &zstr, fullname); - - /* I don't see why we should have to include the 8 byte trailer in - avail_in. But I see that zlib/gzio.c does, and it seemed to fix - a fairly rare bug in which we'd get a Z_BUF_ERROR for no obvious - reason. */ - zstr.avail_in = size - pos; - zstr.next_in = buf + pos; - - crc = crc32 (0, NULL, 0); - - do - { - zstr.avail_out = sizeof (outbuf); - zstr.next_out = outbuf; - zstatus = inflate (&zstr, Z_NO_FLUSH); - if (zstatus != Z_STREAM_END && zstatus != Z_OK) - { - compress_error (0, zstatus, &zstr, fullname); - return 1; - } - if (write (fd, outbuf, sizeof (outbuf) - zstr.avail_out) < 0) - { - error (0, errno, "writing decompressed file %s", fullname); - return 1; - } - crc = crc32 (crc, outbuf, sizeof (outbuf) - zstr.avail_out); - } while (zstatus != Z_STREAM_END); - zstatus = inflateEnd (&zstr); - if (zstatus != Z_OK) - compress_error (0, zstatus, &zstr, fullname); - - /* Check that there is still 8 trailer bytes remaining (CRC32 - and ISIZE). Check total decomp. data, plus header len (pos) - against input buffer total size. */ - pos += zstr.total_in; - if (size - pos != 8) - { - error (0, 0, "gzip data incomplete for %s (no trailer)", fullname); - return 1; - } - - if (crc != ((unsigned long)buf[pos] - + ((unsigned long)buf[pos + 1] << 8) - + ((unsigned long)buf[pos + 2] << 16) - + ((unsigned long)buf[pos + 3] << 24))) - { - error (0, 0, "CRC error uncompressing %s", fullname); - return 1; - } - - if (zstr.total_out != ((unsigned long)buf[pos + 4] - + ((unsigned long)buf[pos + 5] << 8) - + ((unsigned long)buf[pos + 6] << 16) - + ((unsigned long)buf[pos + 7] << 24))) - { - error (0, 0, "invalid length uncompressing %s", fullname); - return 1; - } - - return 0; -} - -/* Read all of FD and put the gzipped data (RFC1952/RFC1951) into *BUF, - replacing previous contents of *BUF. *BUF is xmalloc'd and *SIZE is - its allocated size. Put the actual number of bytes of data in - *LEN. If something goes wrong, give a nonfatal error mentioning - FULLNAME as the name of the file for FD, and return 1 if we can't - recover from it). LEVEL is the compression level (1-9). */ - -int -read_and_gzip (fd, fullname, buf, size, len, level) - int fd; - const char *fullname; - unsigned char **buf; - size_t *size; - size_t *len; - int level; -{ - z_stream zstr; - int zstatus; - unsigned char inbuf[8192]; - int nread; - unsigned long crc; - - if (*size < 1024) - { - unsigned char *newbuf; - - *size = 1024; - newbuf = xrealloc (*buf, *size); - if (newbuf == NULL) - { - error (0, 0, "out of memory"); - return 1; - } - *buf = newbuf; - } - (*buf)[0] = GZIP_ID1; - (*buf)[1] = GZIP_ID2; - (*buf)[2] = GZIP_CDEFLATE; - (*buf)[3] = 0; - (*buf)[4] = (*buf)[5] = (*buf)[6] = (*buf)[7] = 0; - /* Could set this based on level, but why bother? */ - (*buf)[8] = 0; - (*buf)[9] = 255; - - memset (&zstr, 0, sizeof zstr); - zstatus = deflateInit2 (&zstr, level, Z_DEFLATED, -15, 8, - Z_DEFAULT_STRATEGY); - crc = crc32 (0, NULL, 0); - if (zstatus != Z_OK) - { - compress_error (0, zstatus, &zstr, fullname); - return 1; - } - - /* Adjust for 10-byte output header (filled in above) */ - zstr.total_out = 10; - zstr.avail_out = *size - 10; - zstr.next_out = *buf + 10; - - while (1) - { - int finish = 0; - - nread = read (fd, inbuf, sizeof inbuf); - if (nread < 0) - { - error (0, errno, "cannot read %s", fullname); - return 1; - } - else if (nread == 0) - /* End of file. */ - finish = 1; - crc = crc32 (crc, inbuf, nread); - zstr.next_in = inbuf; - zstr.avail_in = nread; - - do - { - /* I don't see this documented anywhere, but deflate seems - to tend to dump core sometimes if we pass it Z_FINISH and - a small (e.g. 2147 byte) avail_out. So we insist on at - least 4096 bytes (that is what zlib/gzio.c uses). */ - - if (zstr.avail_out < 4096) - { - unsigned char *newbuf; - - assert(zstr.avail_out + zstr.total_out == *size); - assert(zstr.next_out == *buf + zstr.total_out); - *size *= 2; - newbuf = xrealloc (*buf, *size); - if (newbuf == NULL) - { - error (0, 0, "out of memory"); - return 1; - } - *buf = newbuf; - zstr.next_out = *buf + zstr.total_out; - zstr.avail_out = *size - zstr.total_out; - assert(zstr.avail_out + zstr.total_out == *size); - assert(zstr.next_out == *buf + zstr.total_out); - } - - zstatus = deflate (&zstr, finish ? Z_FINISH : 0); - if (zstatus == Z_STREAM_END) - goto done; - else if (zstatus != Z_OK) - compress_error (0, zstatus, &zstr, fullname); - } while (zstr.avail_out == 0); - } - done: - /* Need to add the CRC information (8 bytes) - to the end of the gzip'd output. - Ensure there is enough space in the output buffer - to do so. */ - if (zstr.avail_out < 8) - { - unsigned char *newbuf; - - assert(zstr.avail_out + zstr.total_out == *size); - assert(zstr.next_out == *buf + zstr.total_out); - *size += 8 - zstr.avail_out; - newbuf = realloc (*buf, *size); - if (newbuf == NULL) - { - error (0, 0, "out of memory"); - return 1; - } - *buf = newbuf; - zstr.next_out = *buf + zstr.total_out; - zstr.avail_out = *size - zstr.total_out; - assert(zstr.avail_out + zstr.total_out == *size); - assert(zstr.next_out == *buf + zstr.total_out); - } - *zstr.next_out++ = (unsigned char)(crc & 0xff); - *zstr.next_out++ = (unsigned char)((crc >> 8) & 0xff); - *zstr.next_out++ = (unsigned char)((crc >> 16) & 0xff); - *zstr.next_out++ = (unsigned char)((crc >> 24) & 0xff); - - *zstr.next_out++ = (unsigned char)(zstr.total_in & 0xff); - *zstr.next_out++ = (unsigned char)((zstr.total_in >> 8) & 0xff); - *zstr.next_out++ = (unsigned char)((zstr.total_in >> 16) & 0xff); - *zstr.next_out++ = (unsigned char)((zstr.total_in >> 24) & 0xff); - - zstr.total_out += 8; - zstr.avail_out -= 8; - assert(zstr.avail_out + zstr.total_out == *size); - assert(zstr.next_out == *buf + zstr.total_out); - - *len = zstr.total_out; - - zstatus = deflateEnd (&zstr); - if (zstatus != Z_OK) - compress_error (0, zstatus, &zstr, fullname); - - return 0; -} -#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */ |