summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/update.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/update.c')
-rw-r--r--contrib/cvs/src/update.c252
1 files changed, 158 insertions, 94 deletions
diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c
index 89e8323..bec2397 100644
--- a/contrib/cvs/src/update.c
+++ b/contrib/cvs/src/update.c
@@ -96,6 +96,7 @@ static char *tag_update_dir;
static char *join_rev1, *date_rev1;
static char *join_rev2, *date_rev2;
static int aflag = 0;
+static int toss_local_changes = 0;
static int force_tag_match = 1;
static int update_build_dirs = 0;
static int update_prune_dirs = 0;
@@ -112,6 +113,7 @@ static const char *const update_usage[] =
" [-I ign] [-W spec] [files...]\n",
"\t-A\tReset any sticky tags/date/kopts.\n",
"\t-P\tPrune empty directories.\n",
+ "\t-C\tOverwrite locally modified files with clean repository copies.\n",
"\t-d\tBuild directories, like checkout does.\n",
"\t-f\tForce a head revision match if tag/date not found.\n",
"\t-l\tLocal directory only, no recursion.\n",
@@ -147,13 +149,16 @@ update (argc, argv)
/* parse the args */
optind = 0;
- while ((c = getopt (argc, argv, "+ApPflRQqduk:r:D:j:I:W:")) != -1)
+ while ((c = getopt (argc, argv, "+ApCPflRQqduk:r:D:j:I:W:")) != -1)
{
switch (c)
{
case 'A':
aflag = 1;
break;
+ case 'C':
+ toss_local_changes = 1;
+ break;
case 'I':
ign_add (optarg, 0);
break;
@@ -254,6 +259,8 @@ update (argc, argv)
send_arg("-f");
if (aflag)
send_arg("-A");
+ if (toss_local_changes)
+ send_arg("-C");
if (update_prune_dirs)
send_arg("-P");
client_prune_dirs = update_prune_dirs;
@@ -268,28 +275,35 @@ update (argc, argv)
option_with_arg ("-j", join_rev2);
wrap_send ();
- /* If the server supports the command "update-patches", that means
- that it knows how to handle the -u argument to update, which
- means to send patches instead of complete files.
-
- We don't send -u if failed_patches != NULL, so that the
- server doesn't try to send patches which will just fail
- again. At least currently, the client also clobbers the
- file and tells the server it is lost, which also will get
- a full file instead of a patch, but it seems clean to omit
- -u. */
- if (failed_patches == NULL)
+ if (failed_patches_count == 0)
{
+ unsigned int flags = 0;
+
+ /* If the server supports the command "update-patches", that
+ means that it knows how to handle the -u argument to update,
+ which means to send patches instead of complete files.
+
+ We don't send -u if failed_patches != NULL, so that the
+ server doesn't try to send patches which will just fail
+ again. At least currently, the client also clobbers the
+ file and tells the server it is lost, which also will get
+ a full file instead of a patch, but it seems clean to omit
+ -u. */
if (supported_request ("update-patches"))
send_arg ("-u");
- }
- if (failed_patches == NULL)
- {
+ if (update_build_dirs)
+ flags |= SEND_BUILD_DIRS;
+
+ if (toss_local_changes) {
+ flags |= SEND_NO_CONTENTS;
+ flags |= BACKUP_MODIFIED_FILES;
+ }
+
/* If noexec, probably could be setting SEND_NO_CONTENTS.
Same caveats as for "cvs status" apply. */
- send_files (argc, argv, local, aflag,
- update_build_dirs ? SEND_BUILD_DIRS : 0);
+
+ send_files (argc, argv, local, aflag, flags);
send_file_names (argc, argv, SEND_EXPAND_WILD);
}
else
@@ -313,11 +327,9 @@ update (argc, argv)
send_files (failed_patches_count, failed_patches, local,
aflag, update_build_dirs ? SEND_BUILD_DIRS : 0);
send_file_names (failed_patches_count, failed_patches, 0);
+ free_names (&failed_patches_count, failed_patches);
}
- failed_patches = NULL;
- failed_patches_count = 0;
-
send_to_server ("update\012", 0);
status = get_responses_and_close ();
@@ -336,13 +348,15 @@ update (argc, argv)
conflict-and-patch-failed case. */
if (status != 0
- && (failed_patches == NULL || pass > 1))
+ && (failed_patches_count == 0 || pass > 1))
{
+ if (failed_patches_count > 0)
+ free_names (&failed_patches_count, failed_patches);
return status;
}
++pass;
- } while (failed_patches != NULL);
+ } while (failed_patches_count > 0);
return 0;
}
@@ -368,15 +382,20 @@ update (argc, argv)
error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
#ifdef SERVER_SUPPORT
if (server_active)
- server_clear_entstat (".", Name_Repository (NULL, NULL));
+ {
+ char *repos = Name_Repository (NULL, NULL);
+ server_clear_entstat (".", repos);
+ free (repos);
+ }
#endif
}
/* keep the CVS/Tag file current with the specified arguments */
if (aflag || tag || date)
{
- WriteTag ((char *) NULL, tag, date, 0,
- ".", Name_Repository (NULL, NULL));
+ char *repos = Name_Repository (NULL, NULL);
+ WriteTag ((char *) NULL, tag, date, 0, ".", repos);
+ free (repos);
rewrite_tag = 1;
nonbranch = 0;
}
@@ -486,17 +505,11 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
argc, argv, local, which, aflag, 1,
preload_update_dir, 1);
- /* see if we need to sleep before returning */
+ /* see if we need to sleep before returning to avoid time-stamp races */
if (last_register_time)
{
- time_t now;
-
- for (;;)
- {
- (void) time (&now);
- if (now != last_register_time) break;
- sleep (1); /* to avoid time-stamp races */
- }
+ while (time ((time_t *) NULL) == last_register_time)
+ sleep (1);
}
return (err);
@@ -643,54 +656,82 @@ update_fileproc (callerdat, finfo)
break;
case T_MODIFIED: /* locally modified */
retval = 0;
- if (vers->ts_conflict)
- {
- char *filestamp;
- int retcode;
+ if (toss_local_changes)
+ {
+ char *bakname;
+ bakname = backup_file (finfo->file, vers->vn_user);
+ /* This behavior is sufficiently unexpected to
+ justify overinformativeness, I think. */
+#ifdef SERVER_SUPPORT
+ if ((! really_quiet) && (! server_active))
+#else /* ! SERVER_SUPPORT */
+ if (! really_quiet)
+#endif /* SERVER_SUPPORT */
+ (void) printf ("(Locally modified %s moved to %s)\n",
+ finfo->file, bakname);
+ free (bakname);
+
+ /* The locally modified file is still present, but
+ it will be overwritten by the repository copy
+ after this. */
+ status = T_CHECKOUT;
+ retval = checkout_file (finfo, vers, 0, 0, 1);
+ }
+ else
+ {
+ if (vers->ts_conflict)
+ {
+ char *filestamp;
+ int retcode;
+
+ /*
+ * If the timestamp has changed and no
+ * conflict indicators are found, it isn't a
+ * 'C' any more.
+ */
- /*
- * If the timestamp has changed and no conflict indicators
- * are found, it isn't a 'C' any more.
- */
#ifdef SERVER_SUPPORT
- if (server_active)
- retcode = vers->ts_conflict[0] != '=';
- else {
- filestamp = time_stamp (finfo->file);
- retcode = strcmp (vers->ts_conflict, filestamp);
- free (filestamp);
- }
+ if (server_active)
+ retcode = vers->ts_conflict[0] != '=';
+ else
+ {
+ filestamp = time_stamp (finfo->file);
+ retcode = strcmp (vers->ts_conflict, filestamp);
+ free (filestamp);
+ }
#else
- filestamp = time_stamp (finfo->file);
- retcode = strcmp (vers->ts_conflict, filestamp);
- free (filestamp);
+ filestamp = time_stamp (finfo->file);
+ retcode = strcmp (vers->ts_conflict, filestamp);
+ free (filestamp);
#endif
- if (retcode)
- {
- /* The timestamps differ. But if there are conflict
- markers print 'C' anyway. */
- retcode = !file_has_markers (finfo);
- }
-
- if (!retcode)
- {
- write_letter (finfo, 'C');
- retval = 1;
- }
- else
- {
- /* Reregister to clear conflict flag. */
- Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs,
- vers->options, vers->tag,
- vers->date, (char *)0);
- }
- }
- if (!retval)
- {
- write_letter (finfo, 'M');
- retval = 0;
- }
+ if (retcode)
+ {
+ /* The timestamps differ. But if there
+ are conflict markers print 'C' anyway. */
+ retcode = !file_has_markers (finfo);
+ }
+
+ if (!retcode)
+ {
+ write_letter (finfo, 'C');
+ retval = 1;
+ }
+ else
+ {
+ /* Reregister to clear conflict flag. */
+ Register (finfo->entries, finfo->file,
+ vers->vn_rcs, vers->ts_rcs,
+ vers->options, vers->tag,
+ vers->date, (char *)0);
+ }
+ }
+ if (!retval)
+ {
+ write_letter (finfo, 'M');
+ retval = 0;
+ }
+ }
break;
#ifdef SERVER_SUPPORT
case T_PATCH: /* needs patch */
@@ -930,7 +971,8 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
/* This is a guess. We will rewrite it later
via WriteTag. */
0,
- 0);
+ 0,
+ 1);
rewrite_tag = 1;
nonbranch = 0;
Subdir_Register (entries, (char *) NULL, dir);
@@ -1016,6 +1058,10 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries)
{
FILE *fp;
+ /* Delete the ignore list if it hasn't already been done. */
+ if (ignlist)
+ dellist (&ignlist);
+
/* If we set the tag or date for a new subdirectory in
update_dirent_proc, and we're now done with that subdirectory,
undo the tag/date setting. Note that we know that the tag and
@@ -1061,6 +1107,7 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries)
cvs_output (": Executing '", 0);
run_print (stdout);
cvs_output ("'\n", 0);
+ cvs_flushout ();
(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
}
else if (ferror (fp))
@@ -2051,7 +2098,7 @@ join_file (finfo, vers)
Vers_TS *vers;
{
char *backup;
- char *options;
+ char *t_options;
int status;
char *rev1;
@@ -2286,6 +2333,13 @@ join_file (finfo, vers)
xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0);
+ /* Reset any keyword expansion option. Otherwise, when a
+ command like `cvs update -kk -jT1 -jT2' creates a new file
+ (because a file had the T2 tag, but not T1), the subsequent
+ commit of that just-added file effectively would set the
+ admin `-kk' option for that file in the repository. */
+ options = NULL;
+
/* FIXME: If checkout_file fails, we should arrange to
return a non-zero exit status. */
status = checkout_file (finfo, xvers, 1, 0, 1);
@@ -2328,11 +2382,11 @@ join_file (finfo, vers)
if (jdate2 != NULL)
error (0, 0,
- "file %s is present in revision %s as of %s",
+ "file %s does not exist, but is present in revision %s as of %s",
finfo->fullname, jrev2, jdate2);
else
error (0, 0,
- "file %s is present in revision %s",
+ "file %s does not exist, but is present in revision %s",
finfo->fullname, jrev2);
/* FIXME: Should we arrange to return a non-zero exit status? */
@@ -2374,10 +2428,10 @@ join_file (finfo, vers)
copy_file (finfo->file, backup);
xchmod (finfo->file, 1);
- options = vers->options;
+ t_options = vers->options;
#if 0
- if (*options == '\0')
- options = "-kk"; /* to ignore keyword expansions */
+ if (*t_options == '\0')
+ t_options = "-kk"; /* to ignore keyword expansions */
#endif
/* If the source of the merge is the same as the working file
@@ -2395,12 +2449,12 @@ join_file (finfo, vers)
/* This is because of the worry below about $Name. If that
isn't a problem, I suspect this code probably works for
text files too. */
- && (strcmp (options, "-kb") == 0
+ && (strcmp (t_options, "-kb") == 0
|| wrap_merge_is_copy (finfo->file)))
{
/* FIXME: what about nametag? What does RCS_merge do with
$Name? */
- if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options,
+ if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, t_options,
RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
status = 2;
else
@@ -2424,7 +2478,7 @@ join_file (finfo, vers)
print. */
write_letter (finfo, 'U');
}
- else if (strcmp (options, "-kb") == 0
+ else if (strcmp (t_options, "-kb") == 0
|| wrap_merge_is_copy (finfo->file)
|| special_file_mismatch (finfo, rev1, rev2))
{
@@ -2434,7 +2488,7 @@ join_file (finfo, vers)
the two files, and let them resolve it. It is possible
that we should require a "touch foo" or similar step before
we allow a checkin. */
- if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options,
+ if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, t_options,
RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0)
status = 2;
else
@@ -2465,7 +2519,7 @@ join_file (finfo, vers)
}
else
status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
- options, rev1, rev2);
+ t_options, rev1, rev2);
if (status != 0 && status != 1)
{
@@ -2496,9 +2550,9 @@ join_file (finfo, vers)
(void) time (&last_register_time);
cp = time_stamp (finfo->file);
}
- Register (finfo->entries, finfo->file, vers->vn_rcs,
- "Result of merge", vers->options, vers->tag,
- vers->date, cp);
+ Register (finfo->entries, finfo->file,
+ vers->vn_rcs ? vers->vn_rcs : "0", "Result of merge",
+ vers->options, vers->tag, vers->date, cp);
if (cp)
free(cp);
}
@@ -2546,8 +2600,8 @@ special_file_mismatch (finfo, rev1, rev2)
dev_t rev1_dev, rev2_dev;
char *rev1_symlink = NULL;
char *rev2_symlink = NULL;
- List *rev1_hardlinks;
- List *rev2_hardlinks;
+ List *rev1_hardlinks = NULL;
+ List *rev2_hardlinks = NULL;
int check_uids, check_gids, check_modes;
int result;
@@ -2576,6 +2630,7 @@ special_file_mismatch (finfo, rev1, rev2)
rev1_symlink = xreadlink (finfo->file);
else
{
+#ifdef HAVE_ST_RDEV
if (CVS_LSTAT (finfo->file, &sb) < 0)
error (1, errno, "could not get file information for %s",
finfo->file);
@@ -2584,6 +2639,10 @@ special_file_mismatch (finfo, rev1, rev2)
rev1_mode = sb.st_mode;
if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode))
rev1_dev = sb.st_rdev;
+#else
+ error (1, 0, "cannot handle device files on this system (%s)",
+ finfo->file);
+#endif
}
rev1_hardlinks = list_linked_files_on_disk (finfo->file);
}
@@ -2649,6 +2708,7 @@ special_file_mismatch (finfo, rev1, rev2)
rev2_symlink = xreadlink (finfo->file);
else
{
+#ifdef HAVE_ST_RDEV
if (CVS_LSTAT (finfo->file, &sb) < 0)
error (1, errno, "could not get file information for %s",
finfo->file);
@@ -2657,6 +2717,10 @@ special_file_mismatch (finfo, rev1, rev2)
rev2_mode = sb.st_mode;
if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode))
rev2_dev = sb.st_rdev;
+#else
+ error (1, 0, "cannot handle device files on this system (%s)",
+ finfo->file);
+#endif
}
rev2_hardlinks = list_linked_files_on_disk (finfo->file);
}
OpenPOWER on IntegriCloud