Subject: CVS 1.9: RCS_merge Timestamp Anomaly
From: [email-masked] ("Griswold, Victor")

5 Mar 1997 18:27:00 -0800
Approved: [email-masked]
Distribution: cygnus
Message-ID: <c=US%a=_%p=TELXON%l=TELXON/TLXUSEX1/[email-masked]>
Mime-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Original-To: "'Cygnus:GNU-WIN32'" <[email-masked]>,
        "[email-masked]'"
	 <[email-masked]>
X-Mailer: Microsoft Exchange Server Internet Mail Connector Version 4.0.994.63
Original-Sender: [email-masked]

Gentlemen:

Enclosed is a patch to the CVS 1.9 distribution which corrects a subtle
problem with "cvs checkout -j".  The problem is that, on fast
workstations, a checkout followed by a merge can take place within the
time quantum of the filesystem (1 second on Unix, 2 seconds on
DOS/Windows FAT).  The result is that, on a subsequent commit, cvs
compares the checkout timestamp with the file timestamp (which are
equal) and incorrectly believes that no merge had been done on the file.

This patch also stabilizes running sanity.sh somewhat when executing on
fast workstations, particularly ones utilizing the DOS/Windows FAT
filesystem.

The mechanism utilized by the patch is simply to check the file
timestamp before the merge, then after the merge.  If they remain the
same, RCS_merge waits one second, touches the merged file, and checks
again.

This message is cross-posted to the cygnus gnu-win32 mailing list
because of recent interest in CVS in that mailing list.  Future
bug-fixes will be posted only to the bug-cvs mailing list.  For those
interested in that mailing list, subscribe by sending "subscribe
bug-cvs" in a mail message to [email-masked].

Victor J. Griswold, D.Sc.
Aironet Wireless Communications, Inc.
voice:	330-664-7987
fax:	330-664-7301
email:	(MS-Mail) [email-masked]
	(MIME) [email-masked]

Index: CVS_src/ChangeLog
diff -c CVS_src/ChangeLog:1.1.1.1 CVS_src/ChangeLog:1.1.1.1.2.1
*** CVS_src/ChangeLog:1.1.1.1	Wed Dec 31 19:00:49 1969
--- CVS_src/ChangeLog	Wed Dec 31 18:56:32 1969
***************
*** 1,3 ****
--- 1,10 ----
+ Wed Mar  5          1997  Victor Griswold <[email-masked]>
+ 	* Fixed RCS_merge timestamp anomaly in which a merged file could
+ 	have the same timestamp as the original file.  This can occur
+ 	on a fast workstation when executing "cvs checkout -j".  The
+ 	result is that a later "cvs commit" fails to detect the merged
+ 	files because the timestamps are the same.
+ 
  Tue Oct  1 14:32:44 1996  Jim Kingdon  <[email-masked]>
  
  	* NEWS, README: Revert changes regarding -D, -g, and A4.  They
Index: CVS_src/src/cvs.h
diff -c CVS_src/src/cvs.h:1.1.1.1.2.1 CVS_src/src/cvs.h:1.1.1.1.2.2
*** CVS_src/src/cvs.h:1.1.1.1.2.1	Wed Dec 31 18:58:46 1969
--- CVS_src/src/cvs.h	Wed Dec 31 18:56:45 1969
***************
*** 334,340 ****
  typedef enum direnter_type Dtype;
  #endif
  
! extern char *program_name, *program_path, *command_name;
  extern char *Rcsbin, *Tmpdir, *Editor;
  extern int cvsadmin_root;
  extern char *CurDir;
--- 334,341 ----
  typedef enum direnter_type Dtype;
  #endif
  
! extern const char *program_name;
! extern char *program_path, *command_name;
  extern char *Rcsbin, *Tmpdir, *Editor;
  extern int cvsadmin_root;
  extern char *CurDir;
***************
*** 404,410 ****
  char *Short_Repository PROTO((char *repository));
  char *gca PROTO((char *rev1, char *rev2));
  char *getcaller PROTO((void));
! char *time_stamp PROTO((char *file));
  char *xmalloc PROTO((size_t bytes));
  void *xrealloc PROTO((void *ptr, size_t bytes));
  char *xstrdup PROTO((const char *str));
--- 405,411 ----
  char *Short_Repository PROTO((char *repository));
  char *gca PROTO((char *rev1, char *rev2));
  char *getcaller PROTO((void));
! char *time_stamp PROTO((const char *file));
  char *xmalloc PROTO((size_t bytes));
  void *xrealloc PROTO((void *ptr, size_t bytes));
  char *xstrdup PROTO((const char *str));
***************
*** 422,428 ****
  int iswritable PROTO((const char *file));
  int isaccessible PROTO((const char *file, const int mode));
  int isabsolute PROTO((const char *filename));
! char *last_component PROTO((char *path));
  char *get_homedir PROTO ((void));
  char *cvs_temp_name PROTO ((void));
  
--- 423,429 ----
  int iswritable PROTO((const char *file));
  int isaccessible PROTO((const char *file, const int mode));
  int isabsolute PROTO((const char *filename));
! const char *last_component PROTO((const char *path));
  char *get_homedir PROTO ((void));
  char *cvs_temp_name PROTO ((void));
  
Index: CVS_src/src/filesubr.c
diff -c CVS_src/src/filesubr.c:1.1.1.1.2.2
CVS_src/src/filesubr.c:1.1.1.1.2.4
*** CVS_src/src/filesubr.c:1.1.1.1.2.2	Wed Dec 31 18:57:23 1969
--- CVS_src/src/filesubr.c	Wed Dec 31 18:56:47 1969
***************
*** 834,844 ****

  /* Return a pointer into PATH's last component.  */
! char *
! last_component (char *path)
  {
!     char *scan;
!     char *last = 0;
  
      for (scan = path; *scan; scan++)
          if (ISDIRSEP (*scan))
--- 838,848 ----

  /* Return a pointer into PATH's last component.  */
! const char *
! last_component (const char *path)
  {
!     const char *scan;
!     const char *last = 0;
  
      for (scan = path; *scan; scan++)
          if (ISDIRSEP (*scan))
Index: CVS_src/src/main.c
diff -c CVS_src/src/main.c:1.1.1.1.2.1 CVS_src/src/main.c:1.1.1.1.2.2
*** CVS_src/src/main.c:1.1.1.1.2.1	Wed Dec 31 18:57:30 1969
--- CVS_src/src/main.c	Wed Dec 31 18:56:48 1969
***************
*** 20,26 ****
  extern int gethostname ();
  #endif
  
! char *program_name;
  char *program_path;
  char *command_name;
  
--- 20,26 ----
  extern int gethostname ();
  #endif
  
! const char *program_name;
  char *program_path;
  char *command_name;
  
Index: CVS_src/src/rcs.h
diff -c CVS_src/src/rcs.h:1.1.1.1 CVS_src/src/rcs.h:1.1.1.1.2.1
*** CVS_src/src/rcs.h:1.1.1.1	Wed Dec 31 19:00:58 1969
--- CVS_src/src/rcs.h	Wed Dec 31 18:56:49 1969
***************
*** 17,22 ****
--- 17,23 ----
  #define	RCS_RCSMERGE	"rcsmerge"
  #define	RCS_MERGE_PAT	"^>>>>>>> "	/* runs "grep" with this pattern */
  #define	RCSEXT		",v"
+ #define RCSEXT_LEN  (2)
  #define RCSPAT		"*,v"
  #define	RCSHEAD		"head"
  #define	RCSBRANCH	"branch"
Index: CVS_src/src/rcscmds.c
diff -c CVS_src/src/rcscmds.c:1.1.1.1 CVS_src/src/rcscmds.c:1.1.1.1.2.1
*** CVS_src/src/rcscmds.c:1.1.1.1	Wed Dec 31 19:01:02 1969
--- CVS_src/src/rcscmds.c	Wed Dec 31 18:56:50 1969
***************
*** 143,151 ****
--- 143,161 ----
       const char *rev2;
  {
      int status;
+ 	int delay_status;
+ 	const char *archiveName = last_component(path);
+ 	char *userFile;
+ 	char *timeBefore;
+ 	char *timeAfter;
  
      /* XXX - Do merge by hand instead of using rcsmerge, due to -k
handling */
  
+ 	userFile = xstrdup(archiveName);
+ 	userFile[strlen(archiveName) - RCSEXT_LEN] = '\0';
+ 	
+ 	timeBefore = time_stamp(userFile);
+ 
      run_setup ("%s%s -x,v/ %s -r%s -r%s %s", Rcsbin, RCS_RCSMERGE,
  	       options, rev1, rev2, path);
      status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
***************
*** 160,165 ****
--- 170,201 ----
  
      }
  #endif
+ 
+ 	timeAfter = time_stamp(userFile);
+ 	while (timeAfter && strcmp(timeBefore, timeAfter) == 0) {
+ 		free(timeAfter);
+ 
+ 		if (trace) {
+ 			fprintf(stderr, "-> RCS_merge: timestamp of file %s is %s before
and after merge.\n",
+ 					userFile, timeBefore);
+ 		}
+ 				 
+ 		/*		Force the time stamp on the merged file to be different	*/
+ 		/*	if the file was just checked out.  This avoids confusing	*/
+ 		/*	Classify_File.												*/
+ 		/**/
+ 		sleep(1);
+ 		run_setup ("touch %s", userFile);
+ 		delay_status = run_exec (RUN_TTY, DEVNULL, RUN_TTY, RUN_NORMAL);
+ 
+ 		timeAfter = time_stamp(userFile);
+ 	}
+ 
+ 	free(userFile);
+ 	if (timeBefore)
+ 		free(timeBefore);
+ 	if (timeAfter)
+ 		free(timeAfter);
      return status;
  }
  
Index: CVS_src/src/recurse.c
diff -c CVS_src/src/recurse.c:1.1.1.1.2.1
CVS_src/src/recurse.c:1.1.1.1.2.2
*** CVS_src/src/recurse.c:1.1.1.1.2.1	Wed Dec 31 18:59:05 1969
--- CVS_src/src/recurse.c	Wed Dec 31 18:56:51 1969
***************
*** 189,195 ****
  	    /* 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]);
! 	    comp = last_component (dir);
  	    if (comp == dir)
  	    {
  		/* no dir component.  What we have is an implied "./" */
--- 189,195 ----
  	    /* 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]);
! 	    comp = (char*)last_component (dir);
  	    if (comp == dir)
  	    {
  		/* no dir component.  What we have is an implied "./" */
***************
*** 670,676 ****
      }
  
      /* put back update_dir */
!     cp = last_component (update_dir);
      if (cp > update_dir)
  	cp[-1] = '\0';
      else
--- 670,676 ----
      }
  
      /* put back update_dir */
!     cp = (char*)last_component (update_dir);
      if (cp > update_dir)
  	cp[-1] = '\0';
      else
Index: CVS_src/src/vers_ts.c
diff -c CVS_src/src/vers_ts.c:1.1.1.1 CVS_src/src/vers_ts.c:1.1.1.1.2.1
*** CVS_src/src/vers_ts.c:1.1.1.1	Wed Dec 31 19:01:03 1969
--- CVS_src/src/vers_ts.c	Wed Dec 31 18:56:55 1969
***************
*** 274,280 ****
   */
  char *
  time_stamp (file)
!     char *file;
  {
      struct stat sb;
      char *cp;
--- 274,280 ----
   */
  char *
  time_stamp (file)
!     const char *file;
  {
      struct stat sb;
      char *cp;

-
For help on using this list, send a message to
"[email-masked]" with one line of text: "help".