257 |
TRACE (TRACE_FUNCTION, "base_checkout (%s, %s, %s, %s, %s, %s, %s)", |
TRACE (TRACE_FUNCTION, "base_checkout (%s, %s, %s, %s, %s, %s, %s)", |
258 |
finfo->fullname, prev, rev, ptag, tag, poptions, options); |
finfo->fullname, prev, rev, ptag, tag, poptions, options); |
259 |
|
|
260 |
|
if (noexec) |
261 |
|
return 0; |
262 |
|
|
263 |
mkdir_if_needed (CVSADM_BASE); |
mkdir_if_needed (CVSADM_BASE); |
264 |
|
|
265 |
assert (!current_parsed_root->isremote); |
assert (!current_parsed_root->isremote); |
283 |
|
|
284 |
|
|
285 |
|
|
286 |
|
static char * |
287 |
|
temp_checkout (RCSNode *rcs, struct file_info *finfo, |
288 |
|
const char *prev, const char *rev, const char *ptag, |
289 |
|
const char *tag, const char *poptions, const char *options) |
290 |
|
{ |
291 |
|
char *tempfile; |
292 |
|
bool save_noexec; |
293 |
|
|
294 |
|
TRACE (TRACE_FUNCTION, "temp_checkout (%s, %s, %s, %s, %s, %s, %s)", |
295 |
|
finfo->fullname, prev, rev, ptag, tag, poptions, options); |
296 |
|
|
297 |
|
assert (!current_parsed_root->isremote); |
298 |
|
|
299 |
|
tempfile = cvs_temp_name (); |
300 |
|
save_noexec = noexec; |
301 |
|
noexec = false; |
302 |
|
if (RCS_checkout (rcs, tempfile, rev, tag, options, NULL, NULL, NULL)) |
303 |
|
{ |
304 |
|
error (0, 0, "Failed to check out revision %s of `%s'", |
305 |
|
rev, finfo->fullname); |
306 |
|
free (tempfile); |
307 |
|
noexec = save_noexec; |
308 |
|
return NULL; |
309 |
|
} |
310 |
|
noexec = save_noexec; |
311 |
|
|
312 |
|
assert (strcmp (cvs_cmd_name, "export")); |
313 |
|
if (server_active) |
314 |
|
server_temp_checkout (rcs, finfo, prev, rev, ptag, tag, |
315 |
|
poptions, options, tempfile); |
316 |
|
|
317 |
|
return tempfile; |
318 |
|
} |
319 |
|
|
320 |
|
|
321 |
|
|
322 |
|
enum update_existing |
323 |
|
translate_exists (const char *exists) |
324 |
|
{ |
325 |
|
if (*exists == 'n') return UPDATE_ENTRIES_NEW; |
326 |
|
if (*exists == 'y') return UPDATE_ENTRIES_EXISTING; |
327 |
|
if (*exists == 'm') return UPDATE_ENTRIES_EXISTING_OR_NEW; |
328 |
|
/* The error below should only happen due to a programming error or when |
329 |
|
* the server sends a bad response. |
330 |
|
*/ |
331 |
|
error (1, 0, "unknown existence code received from server: `%s'", |
332 |
|
exists); |
333 |
|
assert (!"Internal error"); /* Placate GCC. */ |
334 |
|
} |
335 |
|
|
336 |
|
|
337 |
|
|
338 |
|
/* Validate the existance of FILENAME against whether we think it should exist |
339 |
|
* or not. If it should exist and doesn't, issue a warning and return success. |
340 |
|
* If it shouldn't exist and does, issue a warning and return false to avoid |
341 |
|
* accidentally overwriting a user's changes. |
342 |
|
*/ |
343 |
|
bool |
344 |
|
validate_change (enum update_existing existp, const char *filename, |
345 |
|
const char *fullname) |
346 |
|
{ |
347 |
|
/* Note that checking this separately from writing the file is |
348 |
|
a race condition: if the existence or lack thereof of the |
349 |
|
file changes between now and the actual calls which |
350 |
|
operate on it, we lose. However (a) there are so many |
351 |
|
cases, I'm reluctant to try to fix them all, (b) in some |
352 |
|
cases the system might not even have a system call which |
353 |
|
does the right thing, and (c) it isn't clear this needs to |
354 |
|
work. */ |
355 |
|
if (existp == UPDATE_ENTRIES_EXISTING |
356 |
|
&& !isfile (filename)) |
357 |
|
/* Emit a warning and update the file anyway. */ |
358 |
|
error (0, 0, "warning: %s unexpectedly disappeared", fullname); |
359 |
|
else if (existp == UPDATE_ENTRIES_NEW |
360 |
|
&& isfile (filename)) |
361 |
|
{ |
362 |
|
/* This error might be confusing; it isn't really clear to |
363 |
|
the user what to do about it. Keep in mind that it has |
364 |
|
several causes: (1) something/someone creates the file |
365 |
|
during the time that CVS is running, (2) the repository |
366 |
|
has two files whose names clash for the client because |
367 |
|
of case-insensitivity or similar causes, See 3 for |
368 |
|
additional notes. (3) a special case of this is that a |
369 |
|
file gets renamed for example from a.c to A.C. A |
370 |
|
"cvs update" on a case-insensitive client will get this |
371 |
|
error. In this case and in case 2, the filename |
372 |
|
(short_pathname) printed in the error message will likely _not_ |
373 |
|
have the same case as seen by the user in a directory listing. |
374 |
|
(4) the client has a file which the server doesn't know |
375 |
|
about (e.g. "? foo" file), and that name clashes with a file |
376 |
|
the server does know about, (5) classify.c will print the same |
377 |
|
message for other reasons. |
378 |
|
|
379 |
|
I hope the above paragraph makes it clear that making this |
380 |
|
clearer is not a one-line fix. */ |
381 |
|
error (0, 0, "move away `%s'; it is in the way", fullname); |
382 |
|
|
383 |
|
/* The Mode, Mod-time, and Checksum responses should not carry |
384 |
|
* over to a subsequent Created (or whatever) response, even |
385 |
|
* in the error case. |
386 |
|
*/ |
387 |
|
if (!really_quiet) |
388 |
|
{ |
389 |
|
cvs_output ("C ", 0); |
390 |
|
cvs_output (fullname, 0); |
391 |
|
cvs_output ("\n", 1); |
392 |
|
} |
393 |
|
return false; |
394 |
|
} |
395 |
|
|
396 |
|
return true; |
397 |
|
} |
398 |
|
|
399 |
|
|
400 |
|
|
401 |
void |
void |
402 |
base_copy (struct file_info *finfo, const char *rev, const char *flags) |
base_copy (struct file_info *finfo, const char *rev, const char *flags) |
403 |
{ |
{ |
408 |
|
|
409 |
assert (flags && flags[0] && flags[1]); |
assert (flags && flags[0] && flags[1]); |
410 |
|
|
411 |
|
if (!server_active /* The server still doesn't stay perfectly in sync with |
412 |
|
* the client workspace. |
413 |
|
*/ |
414 |
|
&& !validate_change (translate_exists (flags), finfo->file, |
415 |
|
finfo->fullname)) |
416 |
|
exit (EXIT_FAILURE); |
417 |
|
|
418 |
|
if (noexec) |
419 |
|
return; |
420 |
|
|
421 |
basefile = make_base_file_name (finfo->file, rev); |
basefile = make_base_file_name (finfo->file, rev); |
422 |
if (isfile (finfo->file)) |
if (isfile (finfo->file)) |
423 |
xchmod (finfo->file, true); |
xchmod (finfo->file, true); |
424 |
|
|
425 |
copy_file (basefile, finfo->file); |
copy_file (basefile, finfo->file); |
426 |
if (flags[1] == 'y') |
if (flags[1] == 'y') |
427 |
xchmod (finfo->file, true); |
xchmod (finfo->file, true); |
453 |
int |
int |
454 |
base_merge (RCSNode *rcs, struct file_info *finfo, const char *ptag, |
base_merge (RCSNode *rcs, struct file_info *finfo, const char *ptag, |
455 |
const char *poptions, const char *options, const char *urev, |
const char *poptions, const char *options, const char *urev, |
456 |
const char *rev1, const char *rev2) |
const char *rev1, const char *rev2, bool join) |
457 |
{ |
{ |
458 |
char *f1, *f2; |
char *f1, *f2; |
459 |
int retval; |
int retval; |
465 |
fails is not very informative -- it is taken verbatim from RCS 5.7, |
fails is not very informative -- it is taken verbatim from RCS 5.7, |
466 |
and relies on RCS_checkout saying something intelligent upon failure. */ |
and relies on RCS_checkout saying something intelligent upon failure. */ |
467 |
|
|
468 |
if (base_checkout (rcs, finfo, urev, rev1, ptag, rev1, poptions, options)) |
if (!(f1 = temp_checkout (rcs, finfo, urev, rev1, ptag, rev1, poptions, |
469 |
|
options))) |
470 |
error (1, 0, "checkout of revision %s of `%s' failed.\n", |
error (1, 0, "checkout of revision %s of `%s' failed.\n", |
471 |
rev1, finfo->fullname); |
rev1, finfo->fullname); |
472 |
|
if (join || noexec) |
473 |
|
{ |
474 |
|
if (!(f2 = temp_checkout (rcs, finfo, urev, rev2, ptag, rev2, poptions, |
475 |
|
options))) |
476 |
|
error (1, 0, "checkout of revision %s of `%s' failed.\n", |
477 |
|
rev2, finfo->fullname); |
478 |
|
} |
479 |
|
else |
480 |
|
{ |
481 |
|
if (base_checkout (rcs, finfo, urev, rev2, ptag, rev2, poptions, |
482 |
|
options)) |
483 |
|
error (1, 0, "checkout of revision %s of `%s' failed.\n", |
484 |
|
rev2, finfo->fullname); |
485 |
|
f2 = make_base_file_name (finfo->file, rev2); |
486 |
|
} |
487 |
|
|
|
if (base_checkout (rcs, finfo, urev, rev2, ptag, rev2, poptions, options)) |
|
|
error (1, 0, "checkout of revision %s of `%s' failed.\n", |
|
|
rev2, finfo->fullname); |
|
|
|
|
|
f1 = make_base_file_name (finfo->file, rev1); |
|
|
f2 = make_base_file_name (finfo->file, rev2); |
|
488 |
|
|
489 |
if (!server_active || !server_use_bases()) |
if (!server_active || !server_use_bases()) |
490 |
{ |
{ |
493 |
* files on the server as will be generated on the client, but I do not |
* files on the server as will be generated on the client, but I do not |
494 |
* believe that they are being used currently and it saves server CPU. |
* believe that they are being used currently and it saves server CPU. |
495 |
*/ |
*/ |
496 |
cvs_output ("Merging differences between revisions ", 0); |
if (!really_quiet) |
497 |
cvs_output (rev1, 0); |
{ |
498 |
cvs_output (" and ", 5); |
cvs_output ("Merging differences between ", 0); |
499 |
cvs_output (rev2, 0); |
cvs_output (rev1, 0); |
500 |
cvs_output (" into `", 7); |
cvs_output (" and ", 5); |
501 |
if (!finfo->update_dir || !strcmp (finfo->update_dir, ".")) |
cvs_output (rev2, 0); |
502 |
cvs_output (finfo->file, 0); |
cvs_output (" into `", 7); |
503 |
else |
if (!finfo->update_dir || !strcmp (finfo->update_dir, ".")) |
504 |
cvs_output (finfo->fullname, 0); |
cvs_output (finfo->file, 0); |
505 |
cvs_output ("'\n", 2); |
else |
506 |
|
cvs_output (finfo->fullname, 0); |
507 |
|
cvs_output ("'\n", 2); |
508 |
|
} |
509 |
|
|
510 |
retval = merge (finfo->file, finfo->file, f1, f2, rev1, rev2); |
retval = merge (finfo->file, finfo->file, f1, rev1, f2, rev2); |
511 |
} |
} |
512 |
else |
else |
513 |
retval = 0; |
retval = 0; |
515 |
if (server_active) |
if (server_active) |
516 |
server_base_merge (finfo, rev1, rev2); |
server_base_merge (finfo, rev1, rev2); |
517 |
|
|
518 |
if (strcmp (urev, rev1) && unlink_file (f1) < 0) |
if (CVS_UNLINK (f1) < 0) |
519 |
error (0, errno, "unable to remove `%s'", f1); |
error (0, errno, "unable to remove `%s'", f1); |
520 |
if (strcmp (urev, rev2) && unlink_file (f2) < 0) |
/* Using a base file instead of a temp file here and not deleting it is an |
521 |
error (0, errno, "unable to remove `%s'", f2); |
* optimization since, for instance, on merge from 1.1 to 1.4 with local |
522 |
|
* changes, the client is going to want to leave base 1.4 and delete base |
523 |
|
* 1.1 rather than the other way around. |
524 |
|
*/ |
525 |
|
if (join || noexec) |
526 |
|
{ |
527 |
|
if (CVS_UNLINK (f2) < 0) |
528 |
|
error (0, errno, "unable to remove `%s'", f2); |
529 |
|
} |
530 |
free (f1); |
free (f1); |
531 |
free (f2); |
free (f2); |
532 |
|
|