1 /* 2 * Copyright (c) 1992, Brian Berliner and Jeff Polk 3 * Copyright (c) 1989-1992, Brian Berliner 4 * 5 * You may distribute under the terms of the GNU General Public License as 6 * specified in the README file that comes with the CVS 1.4 kit. 7 * 8 */ 9 10 #include "cvs.h" 11 12 #ifdef SERVER_SUPPORT 13 static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers, 14 List * entries, 15 char *repository, char *update_dir)); 16 #else 17 static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers, List * entries)); 18 #endif 19 20 /* 21 * Classify the state of a file 22 */ 23 Ctype 24 Classify_File (finfo, tag, date, options, force_tag_match, aflag, versp, 25 pipeout) 26 struct file_info *finfo; 27 char *tag; 28 char *date; 29 char *options; 30 int force_tag_match; 31 int aflag; 32 Vers_TS **versp; 33 int pipeout; 34 { 35 Vers_TS *vers; 36 Ctype ret; 37 38 /* get all kinds of good data about the file */ 39 vers = Version_TS (finfo, options, tag, date, 40 force_tag_match, 0); 41 42 if (vers->vn_user == NULL) 43 { 44 /* No entry available, ts_rcs is invalid */ 45 if (vers->vn_rcs == NULL) 46 { 47 /* there is no RCS file either */ 48 if (vers->ts_user == NULL) 49 { 50 /* there is no user file */ 51 if (!force_tag_match || !(vers->tag || vers->date)) 52 if (!really_quiet) 53 error (0, 0, "nothing known about %s", finfo->fullname); 54 ret = T_UNKNOWN; 55 } 56 else 57 { 58 /* there is a user file */ 59 if (!force_tag_match || !(vers->tag || vers->date)) 60 if (!really_quiet) 61 error (0, 0, "use `cvs add' to create an entry for %s", 62 finfo->fullname); 63 ret = T_UNKNOWN; 64 } 65 } 66 else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) 67 { 68 if (vers->ts_user == NULL) 69 ret = T_UPTODATE; 70 else 71 { 72 error (0, 0, "use `cvs add' to create an entry for %s", 73 finfo->fullname); 74 ret = T_UNKNOWN; 75 } 76 } 77 else 78 { 79 /* there is an rcs file */ 80 81 if (vers->ts_user == NULL) 82 { 83 /* There is no user file; needs checkout */ 84 ret = T_CHECKOUT; 85 } 86 else 87 { 88 if (pipeout) 89 { 90 /* 91 * The user file doesn't necessarily have anything 92 * to do with this. 93 */ 94 ret = T_CHECKOUT; 95 } 96 /* 97 * There is a user file; print a warning and add it to the 98 * conflict list, only if it is indeed different from what we 99 * plan to extract 100 */ 101 else if (No_Difference (finfo, vers)) 102 { 103 /* the files were different so it is a conflict */ 104 if (!really_quiet) 105 error (0, 0, "move away %s; it is in the way", 106 finfo->fullname); 107 ret = T_CONFLICT; 108 } 109 else 110 /* since there was no difference, still needs checkout */ 111 ret = T_CHECKOUT; 112 } 113 } 114 } 115 else if (strcmp (vers->vn_user, "0") == 0) 116 { 117 /* An entry for a new-born file; ts_rcs is dummy */ 118 119 if (vers->ts_user == NULL) 120 { 121 /* 122 * There is no user file, but there should be one; remove the 123 * entry 124 */ 125 if (!really_quiet) 126 error (0, 0, "warning: new-born %s has disappeared", finfo->fullname); 127 ret = T_REMOVE_ENTRY; 128 } 129 else 130 { 131 /* There is a user file */ 132 133 if (vers->vn_rcs == NULL) 134 /* There is no RCS file, added file */ 135 ret = T_ADDED; 136 else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) 137 /* we are resurrecting. */ 138 ret = T_ADDED; 139 else 140 { 141 if (vers->srcfile->flags & INATTIC 142 && vers->srcfile->flags & VALID) 143 { 144 /* This file has been added on some branch other than 145 the one we are looking at. In the branch we are 146 looking at, the file was already valid. */ 147 if (!really_quiet) 148 error (0, 0, 149 "\ 150 conflict: %s has been added, but already exists", 151 finfo->fullname); 152 } 153 else 154 { 155 /* 156 * There is an RCS file, so someone else must have checked 157 * one in behind our back; conflict 158 */ 159 if (!really_quiet) 160 error (0, 0, 161 "\ 162 conflict: %s created independently by second party", 163 finfo->fullname); 164 } 165 ret = T_CONFLICT; 166 } 167 } 168 } 169 else if (vers->vn_user[0] == '-') 170 { 171 /* An entry for a removed file, ts_rcs is invalid */ 172 173 if (vers->ts_user == NULL) 174 { 175 char tmp[PATH_MAX]; 176 177 /* There is no user file (as it should be) */ 178 179 (void) sprintf (tmp, "-%s", vers->vn_rcs ? vers->vn_rcs : ""); 180 181 if (vers->vn_rcs == NULL 182 || RCS_isdead (vers->srcfile, vers->vn_rcs)) 183 { 184 185 /* 186 * There is no RCS file; this is all-right, but it has been 187 * removed independently by a second party; remove the entry 188 */ 189 ret = T_REMOVE_ENTRY; 190 } 191 else if (strcmp (tmp, vers->vn_user) == 0) 192 193 /* 194 * The RCS file is the same version as the user file was, and 195 * that's OK; remove it 196 */ 197 ret = T_REMOVED; 198 else 199 { 200 201 /* 202 * The RCS file is a newer version than the removed user file 203 * and this is definitely not OK; make it a conflict. 204 */ 205 if (!really_quiet) 206 error (0, 0, 207 "conflict: removed %s was modified by second party", 208 finfo->fullname); 209 ret = T_CONFLICT; 210 } 211 } 212 else 213 { 214 /* The user file shouldn't be there */ 215 if (!really_quiet) 216 error (0, 0, "%s should be removed and is still there", 217 finfo->fullname); 218 ret = T_REMOVED; 219 } 220 } 221 else 222 { 223 /* A normal entry, TS_Rcs is valid */ 224 if (vers->vn_rcs == NULL) 225 { 226 /* There is no RCS file */ 227 228 if (vers->ts_user == NULL) 229 { 230 /* There is no user file, so just remove the entry */ 231 if (!really_quiet) 232 error (0, 0, "warning: %s is not (any longer) pertinent", 233 finfo->fullname); 234 ret = T_REMOVE_ENTRY; 235 } 236 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) 237 { 238 239 /* 240 * The user file is still unmodified, so just remove it from 241 * the entry list 242 */ 243 if (!really_quiet) 244 error (0, 0, "%s is no longer in the repository", 245 finfo->fullname); 246 ret = T_REMOVE_ENTRY; 247 } 248 else 249 { 250 /* 251 * The user file has been modified and since it is no longer 252 * in the repository, a conflict is raised 253 */ 254 if (No_Difference (finfo, vers)) 255 { 256 /* they are different -> conflict */ 257 if (!really_quiet) 258 error (0, 0, 259 "conflict: %s is modified but no longer in the repository", 260 finfo->fullname); 261 ret = T_CONFLICT; 262 } 263 else 264 { 265 /* they weren't really different */ 266 if (!really_quiet) 267 error (0, 0, 268 "warning: %s is not (any longer) pertinent", 269 finfo->fullname); 270 ret = T_REMOVE_ENTRY; 271 } 272 } 273 } 274 else if (strcmp (vers->vn_rcs, vers->vn_user) == 0) 275 { 276 /* The RCS file is the same version as the user file */ 277 278 if (vers->ts_user == NULL) 279 { 280 281 /* 282 * There is no user file, so note that it was lost and 283 * extract a new version 284 */ 285 if (strcmp (command_name, "update") == 0) 286 if (!really_quiet) 287 error (0, 0, "warning: %s was lost", finfo->fullname); 288 ret = T_CHECKOUT; 289 } 290 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) 291 { 292 293 /* 294 * The user file is still unmodified, so nothing special at 295 * all to do -- no lists updated, unless the sticky -k option 296 * has changed. If the sticky tag has changed, we just need 297 * to re-register the entry 298 */ 299 if (vers->entdata->options && 300 strcmp (vers->entdata->options, vers->options) != 0) 301 ret = T_CHECKOUT; 302 else 303 { 304 #ifdef SERVER_SUPPORT 305 sticky_ck (finfo->file, aflag, vers, finfo->entries, 306 finfo->repository, finfo->update_dir); 307 #else 308 sticky_ck (finfo->file, aflag, vers, finfo->entries); 309 #endif 310 ret = T_UPTODATE; 311 } 312 } 313 else 314 { 315 316 /* 317 * The user file appears to have been modified, but we call 318 * No_Difference to verify that it really has been modified 319 */ 320 if (No_Difference (finfo, vers)) 321 { 322 323 /* 324 * they really are different; modified if we aren't 325 * changing any sticky -k options, else needs merge 326 */ 327 #ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED 328 if (strcmp (vers->entdata->options ? 329 vers->entdata->options : "", vers->options) == 0) 330 ret = T_MODIFIED; 331 else 332 ret = T_NEEDS_MERGE; 333 #else 334 ret = T_MODIFIED; 335 #ifdef SERVER_SUPPORT 336 sticky_ck (finfo->file, aflag, vers, finfo->entries, 337 finfo->repository, finfo->update_dir); 338 #else 339 sticky_ck (finfo->file, aflag, vers, finfo->entries); 340 #endif /* SERVER_SUPPORT */ 341 #endif 342 } 343 else 344 { 345 /* file has not changed; check out if -k changed */ 346 if (strcmp (vers->entdata->options ? 347 vers->entdata->options : "", vers->options) != 0) 348 { 349 ret = T_CHECKOUT; 350 } 351 else 352 { 353 354 /* 355 * else -> note that No_Difference will Register the 356 * file already for us, using the new tag/date. This 357 * is the desired behaviour 358 */ 359 ret = T_UPTODATE; 360 } 361 } 362 } 363 } 364 else 365 { 366 /* The RCS file is a newer version than the user file */ 367 368 if (vers->ts_user == NULL) 369 { 370 /* There is no user file, so just get it */ 371 372 if (strcmp (command_name, "update") == 0) 373 if (!really_quiet) 374 error (0, 0, "warning: %s was lost", finfo->fullname); 375 ret = T_CHECKOUT; 376 } 377 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) 378 { 379 380 /* 381 * The user file is still unmodified, so just get it as well 382 */ 383 #ifdef SERVER_SUPPORT 384 if (strcmp (vers->entdata->options ? 385 vers->entdata->options : "", vers->options) != 0 386 || (vers->srcfile != NULL 387 && (vers->srcfile->flags & INATTIC) != 0)) 388 ret = T_CHECKOUT; 389 else 390 ret = T_PATCH; 391 #else 392 ret = T_CHECKOUT; 393 #endif 394 } 395 else 396 { 397 if (No_Difference (finfo, vers)) 398 /* really modified, needs to merge */ 399 ret = T_NEEDS_MERGE; 400 #ifdef SERVER_SUPPORT 401 else if ((strcmp (vers->entdata->options ? 402 vers->entdata->options : "", vers->options) 403 != 0) 404 || (vers->srcfile != NULL 405 && (vers->srcfile->flags & INATTIC) != 0)) 406 /* not really modified, check it out */ 407 ret = T_CHECKOUT; 408 else 409 ret = T_PATCH; 410 #else 411 else 412 /* not really modified, check it out */ 413 ret = T_CHECKOUT; 414 #endif 415 } 416 } 417 } 418 419 /* free up the vers struct, or just return it */ 420 if (versp != (Vers_TS **) NULL) 421 *versp = vers; 422 else 423 freevers_ts (&vers); 424 425 /* return the status of the file */ 426 return (ret); 427 } 428 429 static void 430 #ifdef SERVER_SUPPORT 431 sticky_ck (file, aflag, vers, entries, repository, update_dir) 432 #else 433 sticky_ck (file, aflag, vers, entries) 434 #endif 435 char *file; 436 int aflag; 437 Vers_TS *vers; 438 List *entries; 439 #ifdef SERVER_SUPPORT 440 char *repository; 441 char *update_dir; 442 #endif 443 { 444 if (aflag || vers->tag || vers->date) 445 { 446 char *enttag = vers->entdata->tag; 447 char *entdate = vers->entdata->date; 448 449 if ((enttag && vers->tag && strcmp (enttag, vers->tag)) || 450 ((enttag && !vers->tag) || (!enttag && vers->tag)) || 451 (entdate && vers->date && strcmp (entdate, vers->date)) || 452 ((entdate && !vers->date) || (!entdate && vers->date))) 453 { 454 Register (entries, file, vers->vn_user, vers->ts_rcs, 455 vers->options, vers->tag, vers->date, vers->ts_conflict); 456 457 #ifdef SERVER_SUPPORT 458 if (server_active) 459 { 460 /* We need to update the entries line on the client side. 461 It is possible we will later update it again via 462 server_updated or some such, but that is OK. */ 463 server_update_entries 464 (file, update_dir, repository, 465 strcmp (vers->ts_rcs, vers->ts_user) == 0 ? 466 SERVER_UPDATED : SERVER_MERGED); 467 } 468 #endif 469 } 470 } 471 } 472