| File: | src/gnu/usr.bin/cvs/src/import.c |
| Warning: | line 1370, column 11 Access to field '_flags' results in a dereference of a null pointer (loaded from variable 'fpuser') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 source distribution. | |||
| 7 | * | |||
| 8 | * "import" checks in the vendor release located in the current directory into | |||
| 9 | * the CVS source repository. The CVS vendor branch support is utilized. | |||
| 10 | * | |||
| 11 | * At least three arguments are expected to follow the options: | |||
| 12 | * repository Where the source belongs relative to the CVSROOT | |||
| 13 | * VendorTag Vendor's major tag | |||
| 14 | * VendorReleTag Tag for this particular release | |||
| 15 | * | |||
| 16 | * Additional arguments specify more Vendor Release Tags. | |||
| 17 | */ | |||
| 18 | ||||
| 19 | #include "cvs.h" | |||
| 20 | #include "savecwd.h" | |||
| 21 | #include <assert.h> | |||
| 22 | ||||
| 23 | static char *get_comment PROTO((char *user))(char *user); | |||
| 24 | static int add_rev PROTO((char *message, RCSNode *rcs, char *vfile,(char *message, RCSNode *rcs, char *vfile, char *vers) | |||
| 25 | char *vers))(char *message, RCSNode *rcs, char *vfile, char *vers); | |||
| 26 | static int add_tags PROTO((RCSNode *rcs, char *vfile, char *vtag, int targc,(RCSNode *rcs, char *vfile, char *vtag, int targc, char *targv []) | |||
| 27 | char *targv[]))(RCSNode *rcs, char *vfile, char *vtag, int targc, char *targv []); | |||
| 28 | static int import_descend PROTO((char *message, char *vtag, int targc, char *targv[]))(char *message, char *vtag, int targc, char *targv[]); | |||
| 29 | static int import_descend_dir PROTO((char *message, char *dir, char *vtag,(char *message, char *dir, char *vtag, int targc, char *targv []) | |||
| 30 | int targc, char *targv[]))(char *message, char *dir, char *vtag, int targc, char *targv []); | |||
| 31 | static int process_import_file PROTO((char *message, char *vfile, char *vtag,(char *message, char *vfile, char *vtag, int targc, char *targv []) | |||
| 32 | int targc, char *targv[]))(char *message, char *vfile, char *vtag, int targc, char *targv []); | |||
| 33 | static int update_rcs_file PROTO((char *message, char *vfile, char *vtag, int targc,(char *message, char *vfile, char *vtag, int targc, char *targv [], int inattic) | |||
| 34 | char *targv[], int inattic))(char *message, char *vfile, char *vtag, int targc, char *targv [], int inattic); | |||
| 35 | static void add_log PROTO((int ch, char *fname))(int ch, char *fname); | |||
| 36 | ||||
| 37 | static int repos_len; | |||
| 38 | static char *vhead; | |||
| 39 | static char *vbranch; | |||
| 40 | static FILE *logfp; | |||
| 41 | static char *repository; | |||
| 42 | static int conflicts; | |||
| 43 | static int use_file_modtime; | |||
| 44 | static char *keyword_opt = NULL((void*)0); | |||
| 45 | ||||
| 46 | static const char *const import_usage[] = | |||
| 47 | { | |||
| 48 | "Usage: %s %s [-d] [-k subst] [-I ign] [-m msg] [-b branch]\n", | |||
| 49 | " [-W spec] repository vendor-tag release-tags...\n", | |||
| 50 | "\t-d\tUse the file's modification time as the time of import.\n", | |||
| 51 | "\t-k sub\tSet default RCS keyword substitution mode.\n", | |||
| 52 | "\t-I ign\tMore files to ignore (! to reset).\n", | |||
| 53 | "\t-b bra\tVendor branch id.\n", | |||
| 54 | "\t-m msg\tLog message.\n", | |||
| 55 | "\t-W spec\tWrappers specification line.\n", | |||
| 56 | "(Specify the --help global option for a list of other help options)\n", | |||
| 57 | NULL((void*)0) | |||
| 58 | }; | |||
| 59 | ||||
| 60 | int | |||
| 61 | import (argc, argv) | |||
| 62 | int argc; | |||
| 63 | char **argv; | |||
| 64 | { | |||
| 65 | char *message = NULL((void*)0); | |||
| 66 | char *tmpfile; | |||
| 67 | char *cp; | |||
| 68 | int i, c, msglen, err; | |||
| 69 | List *ulist; | |||
| 70 | Node *p; | |||
| 71 | struct logfile_info *li; | |||
| 72 | ||||
| 73 | if (argc == -1) | |||
| 74 | usage (import_usage); | |||
| 75 | ||||
| 76 | ign_setup (); | |||
| 77 | wrap_setup (); | |||
| 78 | ||||
| 79 | vbranch = xstrdup (CVSBRANCH"1.1.1"); | |||
| 80 | optind = 0; | |||
| 81 | while ((c = getopt (argc, argv, "+Qqdb:m:I:k:W:")) != -1) | |||
| 82 | { | |||
| 83 | switch (c) | |||
| 84 | { | |||
| 85 | case 'Q': | |||
| 86 | case 'q': | |||
| 87 | #ifdef SERVER_SUPPORT1 | |||
| 88 | /* The CVS 1.5 client sends these options (in addition to | |||
| 89 | Global_option requests), so we must ignore them. */ | |||
| 90 | if (!server_active) | |||
| 91 | #endif | |||
| 92 | error (1, 0, | |||
| 93 | "-q or -Q must be specified before \"%s\"", | |||
| 94 | command_name); | |||
| 95 | break; | |||
| 96 | case 'd': | |||
| 97 | #ifdef SERVER_SUPPORT1 | |||
| 98 | if (server_active) | |||
| 99 | { | |||
| 100 | /* CVS 1.10 and older clients will send this, but it | |||
| 101 | doesn't do any good. So tell the user we can't | |||
| 102 | cope, rather than silently losing. */ | |||
| 103 | error (0, 0, | |||
| 104 | "warning: not setting the time of import from the file"); | |||
| 105 | error (0, 0, "due to client limitations"); | |||
| 106 | } | |||
| 107 | #endif | |||
| 108 | use_file_modtime = 1; | |||
| 109 | break; | |||
| 110 | case 'b': | |||
| 111 | free (vbranch); | |||
| 112 | vbranch = xstrdup (optarg); | |||
| 113 | break; | |||
| 114 | case 'm': | |||
| 115 | #ifdef FORCE_USE_EDITOR | |||
| 116 | use_editor = 1; | |||
| 117 | #else | |||
| 118 | use_editor = 0; | |||
| 119 | #endif | |||
| 120 | message = xstrdup(optarg); | |||
| 121 | break; | |||
| 122 | case 'I': | |||
| 123 | ign_add (optarg, 0); | |||
| 124 | break; | |||
| 125 | case 'k': | |||
| 126 | /* RCS_check_kflag returns strings of the form -kxx. We | |||
| 127 | only use it for validation, so we can free the value | |||
| 128 | as soon as it is returned. */ | |||
| 129 | free (RCS_check_kflag (optarg)); | |||
| 130 | keyword_opt = optarg; | |||
| 131 | break; | |||
| 132 | case 'W': | |||
| 133 | wrap_add (optarg, 0); | |||
| 134 | break; | |||
| 135 | case '?': | |||
| 136 | default: | |||
| 137 | usage (import_usage); | |||
| 138 | break; | |||
| 139 | } | |||
| 140 | } | |||
| 141 | argc -= optind; | |||
| 142 | argv += optind; | |||
| 143 | if (argc < 3) | |||
| 144 | usage (import_usage); | |||
| 145 | ||||
| 146 | #ifdef SERVER_SUPPORT1 | |||
| 147 | /* This is for handling the Checkin-time request. It might seem a | |||
| 148 | bit odd to enable the use_file_modtime code even in the case | |||
| 149 | where Checkin-time was not sent for a particular file. The | |||
| 150 | effect is that we use the time of upload, rather than the time | |||
| 151 | when we call RCS_checkin. Since those times are both during | |||
| 152 | CVS's run, that seems OK, and it is easier to implement than | |||
| 153 | putting the "was Checkin-time sent" flag in CVS/Entries or some | |||
| 154 | such place. */ | |||
| 155 | ||||
| 156 | if (server_active) | |||
| 157 | use_file_modtime = 1; | |||
| 158 | #endif | |||
| 159 | ||||
| 160 | for (i = 1; i < argc; i++) /* check the tags for validity */ | |||
| 161 | { | |||
| 162 | int j; | |||
| 163 | ||||
| 164 | RCS_check_tag (argv[i]); | |||
| 165 | for (j = 1; j < i; j++) | |||
| 166 | if (strcmp (argv[j], argv[i]) == 0) | |||
| 167 | error (1, 0, "tag `%s' was specified more than once", argv[i]); | |||
| 168 | } | |||
| 169 | ||||
| 170 | /* XXX - this should be a module, not just a pathname */ | |||
| 171 | if (! isabsolute (argv[0]) | |||
| 172 | && pathname_levels (argv[0]) == 0) | |||
| 173 | { | |||
| 174 | if (current_parsed_root == NULL((void*)0)) | |||
| 175 | { | |||
| 176 | error (0, 0, "missing CVSROOT environment variable\n"); | |||
| 177 | error (1, 0, "Set it or specify the '-d' option to %s.", | |||
| 178 | program_name); | |||
| 179 | } | |||
| 180 | repository = xmalloc (strlen (current_parsed_root->directory) | |||
| 181 | + strlen (argv[0]) | |||
| 182 | + 2); | |||
| 183 | (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); | |||
| 184 | repos_len = strlen (current_parsed_root->directory); | |||
| 185 | } | |||
| 186 | else | |||
| 187 | { | |||
| 188 | /* It is somewhere between a security hole and "unexpected" to | |||
| 189 | let the client start mucking around outside the cvsroot | |||
| 190 | (wouldn't get the right CVSROOT configuration, &c). */ | |||
| 191 | error (1, 0, "directory %s not relative within the repository", | |||
| 192 | argv[0]); | |||
| 193 | } | |||
| 194 | ||||
| 195 | /* | |||
| 196 | * Consistency checks on the specified vendor branch. It must be | |||
| 197 | * composed of only numbers and dots ('.'). Also, for now we only | |||
| 198 | * support branching to a single level, so the specified vendor branch | |||
| 199 | * must only have two dots in it (like "1.1.1"). | |||
| 200 | */ | |||
| 201 | for (cp = vbranch; *cp != '\0'; cp++) | |||
| 202 | if (!isdigit ((unsigned char) *cp) && *cp != '.') | |||
| 203 | error (1, 0, "%s is not a numeric branch", vbranch); | |||
| 204 | if (numdots (vbranch) != 2) | |||
| 205 | error (1, 0, "Only branches with two dots are supported: %s", vbranch); | |||
| 206 | vhead = xstrdup (vbranch); | |||
| 207 | cp = strrchr (vhead, '.'); | |||
| 208 | *cp = '\0'; | |||
| 209 | ||||
| 210 | #ifdef CLIENT_SUPPORT1 | |||
| 211 | if (current_parsed_root->isremote) | |||
| 212 | { | |||
| 213 | /* For rationale behind calling start_server before do_editor, see | |||
| 214 | commit.c */ | |||
| 215 | start_server (); | |||
| 216 | } | |||
| 217 | #endif | |||
| 218 | ||||
| 219 | if (use_editor) | |||
| 220 | { | |||
| 221 | do_editor ((char *) NULL((void*)0), &message, repository, | |||
| 222 | (List *) NULL((void*)0)); | |||
| 223 | } | |||
| 224 | do_verify (message, repository); | |||
| 225 | msglen = message == NULL((void*)0) ? 0 : strlen (message); | |||
| 226 | if (msglen == 0 || message[msglen - 1] != '\n') | |||
| 227 | { | |||
| 228 | char *nm = xmalloc (msglen + 2); | |||
| 229 | *nm = '\0'; | |||
| 230 | if (message != NULL((void*)0)) | |||
| 231 | { | |||
| 232 | (void) strcpy (nm, message); | |||
| 233 | free (message); | |||
| 234 | } | |||
| 235 | (void) strcat (nm + msglen, "\n"); | |||
| 236 | message = nm; | |||
| 237 | } | |||
| 238 | ||||
| 239 | #ifdef CLIENT_SUPPORT1 | |||
| 240 | if (current_parsed_root->isremote) | |||
| 241 | { | |||
| 242 | int err; | |||
| 243 | ||||
| 244 | if (vbranch[0] != '\0') | |||
| 245 | option_with_arg ("-b", vbranch); | |||
| 246 | if (message) | |||
| 247 | option_with_arg ("-m", message); | |||
| 248 | if (keyword_opt != NULL((void*)0)) | |||
| 249 | option_with_arg ("-k", keyword_opt); | |||
| 250 | /* The only ignore processing which takes place on the server side | |||
| 251 | is the CVSROOT/cvsignore file. But if the user specified -I !, | |||
| 252 | the documented behavior is to not process said file. */ | |||
| 253 | if (ign_inhibit_server) | |||
| 254 | { | |||
| 255 | send_arg ("-I"); | |||
| 256 | send_arg ("!"); | |||
| 257 | } | |||
| 258 | wrap_send (); | |||
| 259 | ||||
| 260 | { | |||
| 261 | int i; | |||
| 262 | for (i = 0; i < argc; ++i) | |||
| 263 | send_arg (argv[i]); | |||
| 264 | } | |||
| 265 | ||||
| 266 | logfp = stdin(&__sF[0]); | |||
| 267 | client_import_setup (repository); | |||
| 268 | err = import_descend (message, argv[1], argc - 2, argv + 2); | |||
| 269 | client_import_done (); | |||
| 270 | if (message) | |||
| 271 | free (message); | |||
| 272 | free (repository); | |||
| 273 | free (vbranch); | |||
| 274 | free (vhead); | |||
| 275 | send_to_server ("import\012", 0); | |||
| 276 | err += get_responses_and_close (); | |||
| 277 | return err; | |||
| 278 | } | |||
| 279 | #endif | |||
| 280 | ||||
| 281 | if (!safe_location ()) | |||
| 282 | { | |||
| 283 | error (1, 0, "attempt to import the repository"); | |||
| 284 | } | |||
| 285 | ||||
| 286 | /* | |||
| 287 | * Make all newly created directories writable. Should really use a more | |||
| 288 | * sophisticated security mechanism here. | |||
| 289 | */ | |||
| 290 | (void) umask (cvsumask); | |||
| 291 | make_directories (repository); | |||
| 292 | ||||
| 293 | /* Create the logfile that will be logged upon completion */ | |||
| 294 | if ((logfp = cvs_temp_file (&tmpfile)) == NULL((void*)0)) | |||
| 295 | error (1, errno(*__errno()), "cannot create temporary file `%s'", tmpfile); | |||
| 296 | /* On systems where we can unlink an open file, do so, so it will go | |||
| 297 | away no matter how we exit. FIXME-maybe: Should be checking for | |||
| 298 | errors but I'm not sure which error(s) we get if we are on a system | |||
| 299 | where one can't unlink open files. */ | |||
| 300 | (void) CVS_UNLINKunlink (tmpfile); | |||
| 301 | (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]); | |||
| 302 | (void) fprintf (logfp, "Release Tags:\t"); | |||
| 303 | for (i = 2; i < argc; i++) | |||
| 304 | (void) fprintf (logfp, "%s\n\t\t", argv[i]); | |||
| 305 | (void) fprintf (logfp, "\n"); | |||
| 306 | ||||
| 307 | /* Just Do It. */ | |||
| 308 | err = import_descend (message, argv[1], argc - 2, argv + 2); | |||
| 309 | if (conflicts) | |||
| 310 | { | |||
| 311 | if (!really_quiet) | |||
| 312 | { | |||
| 313 | char buf[20]; | |||
| 314 | char *buf2; | |||
| 315 | ||||
| 316 | cvs_output_tagged ("+importmergecmd", NULL((void*)0)); | |||
| 317 | cvs_output_tagged ("newline", NULL((void*)0)); | |||
| 318 | sprintf (buf, "%d", conflicts); | |||
| 319 | cvs_output_tagged ("conflicts", buf); | |||
| 320 | cvs_output_tagged ("text", " conflicts created by this import."); | |||
| 321 | cvs_output_tagged ("newline", NULL((void*)0)); | |||
| 322 | cvs_output_tagged ("text", | |||
| 323 | "Use the following command to help the merge:"); | |||
| 324 | cvs_output_tagged ("newline", NULL((void*)0)); | |||
| 325 | cvs_output_tagged ("newline", NULL((void*)0)); | |||
| 326 | cvs_output_tagged ("text", "\t"); | |||
| 327 | cvs_output_tagged ("text", program_name); | |||
| 328 | if (CVSroot_cmdline != NULL((void*)0)) | |||
| 329 | { | |||
| 330 | cvs_output_tagged ("text", " -d "); | |||
| 331 | cvs_output_tagged ("text", CVSroot_cmdline); | |||
| 332 | } | |||
| 333 | cvs_output_tagged ("text", " checkout -j"); | |||
| 334 | buf2 = xmalloc (strlen (argv[1]) + 20); | |||
| 335 | sprintf (buf2, "%s:yesterday", argv[1]); | |||
| 336 | cvs_output_tagged ("mergetag1", buf2); | |||
| 337 | free (buf2); | |||
| 338 | cvs_output_tagged ("text", " -j"); | |||
| 339 | cvs_output_tagged ("mergetag2", argv[1]); | |||
| 340 | cvs_output_tagged ("text", " "); | |||
| 341 | cvs_output_tagged ("repository", argv[0]); | |||
| 342 | cvs_output_tagged ("newline", NULL((void*)0)); | |||
| 343 | cvs_output_tagged ("newline", NULL((void*)0)); | |||
| 344 | cvs_output_tagged ("-importmergecmd", NULL((void*)0)); | |||
| 345 | } | |||
| 346 | ||||
| 347 | /* FIXME: I'm not sure whether we need to put this information | |||
| 348 | into the loginfo. If we do, then note that it does not | |||
| 349 | report any required -d option. There is no particularly | |||
| 350 | clean way to tell the server about the -d option used by | |||
| 351 | the client. */ | |||
| 352 | (void) fprintf (logfp, "\n%d conflicts created by this import.\n", | |||
| 353 | conflicts); | |||
| 354 | (void) fprintf (logfp, | |||
| 355 | "Use the following command to help the merge:\n\n"); | |||
| 356 | (void) fprintf (logfp, "\t%s checkout ", program_name); | |||
| 357 | (void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n", | |||
| 358 | argv[1], argv[1], argv[0]); | |||
| 359 | } | |||
| 360 | else | |||
| 361 | { | |||
| 362 | if (!really_quiet) | |||
| 363 | cvs_output ("\nNo conflicts created by this import\n\n", 0); | |||
| 364 | (void) fprintf (logfp, "\nNo conflicts created by this import\n\n"); | |||
| 365 | } | |||
| 366 | ||||
| 367 | /* | |||
| 368 | * Write out the logfile and clean up. | |||
| 369 | */ | |||
| 370 | ulist = getlist (); | |||
| 371 | p = getnode (); | |||
| 372 | p->type = UPDATE; | |||
| 373 | p->delproc = update_delproc; | |||
| 374 | p->key = xstrdup ("- Imported sources"); | |||
| 375 | li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info)); | |||
| 376 | li->type = T_TITLE; | |||
| 377 | li->tag = xstrdup (vbranch); | |||
| 378 | li->rev_old = li->rev_new = NULL((void*)0); | |||
| 379 | p->data = (char *) li; | |||
| 380 | (void) addnode (ulist, p); | |||
| 381 | Update_Logfile (repository, message, logfp, ulist); | |||
| 382 | dellist (&ulist); | |||
| 383 | if (fclose (logfp) < 0) | |||
| 384 | error (0, errno(*__errno()), "error closing %s", tmpfile); | |||
| 385 | ||||
| 386 | /* Make sure the temporary file goes away, even on systems that don't let | |||
| 387 | you delete a file that's in use. */ | |||
| 388 | if (CVS_UNLINKunlink (tmpfile) < 0 && !existence_error (errno)(((*__errno())) == 2)) | |||
| 389 | error (0, errno(*__errno()), "cannot remove %s", tmpfile); | |||
| 390 | free (tmpfile); | |||
| 391 | ||||
| 392 | if (message) | |||
| 393 | free (message); | |||
| 394 | free (repository); | |||
| 395 | free (vbranch); | |||
| 396 | free (vhead); | |||
| 397 | ||||
| 398 | return (err); | |||
| 399 | } | |||
| 400 | ||||
| 401 | /* Process all the files in ".", then descend into other directories. | |||
| 402 | Returns 0 for success, or >0 on error (in which case a message | |||
| 403 | will have been printed). */ | |||
| 404 | static int | |||
| 405 | import_descend (message, vtag, targc, targv) | |||
| 406 | char *message; | |||
| 407 | char *vtag; | |||
| 408 | int targc; | |||
| 409 | char *targv[]; | |||
| 410 | { | |||
| 411 | DIR *dirp; | |||
| 412 | struct dirent *dp; | |||
| 413 | int err = 0; | |||
| 414 | List *dirlist = NULL((void*)0); | |||
| 415 | ||||
| 416 | /* first, load up any per-directory ignore lists */ | |||
| 417 | ign_add_file (CVSDOTIGNORE".cvsignore", 1); | |||
| 418 | wrap_add_file (CVSDOTWRAPPER".cvswrappers", 1); | |||
| 419 | ||||
| 420 | if ((dirp = CVS_OPENDIRopendir (".")) == NULL((void*)0)) | |||
| 421 | { | |||
| 422 | error (0, errno(*__errno()), "cannot open directory"); | |||
| 423 | err++; | |||
| 424 | } | |||
| 425 | else | |||
| 426 | { | |||
| 427 | errno(*__errno()) = 0; | |||
| 428 | while ((dp = CVS_READDIRreaddir (dirp)) != NULL((void*)0)) | |||
| 429 | { | |||
| 430 | if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0) | |||
| 431 | goto one_more_time_boys; | |||
| 432 | #ifdef SERVER_SUPPORT1 | |||
| 433 | /* CVS directories are created in the temp directory by | |||
| 434 | server.c because it doesn't special-case import. So | |||
| 435 | don't print a message about them, regardless of -I!. */ | |||
| 436 | if (server_active && strcmp (dp->d_name, CVSADM"CVS") == 0) | |||
| 437 | goto one_more_time_boys; | |||
| 438 | #endif | |||
| 439 | if (ign_name (dp->d_name)) | |||
| 440 | { | |||
| 441 | add_log ('I', dp->d_name); | |||
| 442 | goto one_more_time_boys; | |||
| 443 | } | |||
| 444 | ||||
| 445 | if ( | |||
| 446 | #ifdef DT_DIR4 | |||
| 447 | (dp->d_type == DT_DIR4 | |||
| 448 | || (dp->d_type == DT_UNKNOWN0 && isdir (dp->d_name))) | |||
| 449 | #else | |||
| 450 | isdir (dp->d_name) | |||
| 451 | #endif | |||
| 452 | && !wrap_name_has (dp->d_name, WRAP_TOCVS) | |||
| 453 | ) | |||
| 454 | { | |||
| 455 | Node *n; | |||
| 456 | ||||
| 457 | if (dirlist == NULL((void*)0)) | |||
| 458 | dirlist = getlist(); | |||
| 459 | ||||
| 460 | n = getnode(); | |||
| 461 | n->key = xstrdup (dp->d_name); | |||
| 462 | addnode(dirlist, n); | |||
| 463 | } | |||
| 464 | else if ( | |||
| 465 | #ifdef DT_DIR4 | |||
| 466 | dp->d_type == DT_LNK10 | |||
| 467 | || (dp->d_type == DT_UNKNOWN0 && islink (dp->d_name)) | |||
| 468 | #else | |||
| 469 | islink (dp->d_name) | |||
| 470 | #endif | |||
| 471 | ) | |||
| 472 | { | |||
| 473 | add_log ('L', dp->d_name); | |||
| 474 | err++; | |||
| 475 | } | |||
| 476 | else | |||
| 477 | { | |||
| 478 | #ifdef CLIENT_SUPPORT1 | |||
| 479 | if (current_parsed_root->isremote) | |||
| 480 | err += client_process_import_file (message, dp->d_name, | |||
| 481 | vtag, targc, targv, | |||
| 482 | repository, | |||
| 483 | keyword_opt != NULL((void*)0) && | |||
| 484 | keyword_opt[0] == 'b', | |||
| 485 | use_file_modtime); | |||
| 486 | else | |||
| 487 | #endif | |||
| 488 | err += process_import_file (message, dp->d_name, | |||
| 489 | vtag, targc, targv); | |||
| 490 | } | |||
| 491 | one_more_time_boys: | |||
| 492 | errno(*__errno()) = 0; | |||
| 493 | } | |||
| 494 | if (errno(*__errno()) != 0) | |||
| 495 | { | |||
| 496 | error (0, errno(*__errno()), "cannot read directory"); | |||
| 497 | ++err; | |||
| 498 | } | |||
| 499 | (void) CVS_CLOSEDIRclosedir (dirp); | |||
| 500 | } | |||
| 501 | ||||
| 502 | if (dirlist != NULL((void*)0)) | |||
| 503 | { | |||
| 504 | Node *head, *p; | |||
| 505 | ||||
| 506 | head = dirlist->list; | |||
| 507 | for (p = head->next; p != head; p = p->next) | |||
| 508 | { | |||
| 509 | err += import_descend_dir (message, p->key, vtag, targc, targv); | |||
| 510 | } | |||
| 511 | ||||
| 512 | dellist(&dirlist); | |||
| 513 | } | |||
| 514 | ||||
| 515 | return (err); | |||
| 516 | } | |||
| 517 | ||||
| 518 | /* | |||
| 519 | * Process the argument import file. | |||
| 520 | */ | |||
| 521 | static int | |||
| 522 | process_import_file (message, vfile, vtag, targc, targv) | |||
| 523 | char *message; | |||
| 524 | char *vfile; | |||
| 525 | char *vtag; | |||
| 526 | int targc; | |||
| 527 | char *targv[]; | |||
| 528 | { | |||
| 529 | char *rcs; | |||
| 530 | int inattic = 0; | |||
| 531 | ||||
| 532 | rcs = xmalloc (strlen (repository) + strlen (vfile) + sizeof (RCSEXT",v") | |||
| 533 | + 5); | |||
| 534 | (void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT",v"); | |||
| 535 | if (!isfile (rcs)) | |||
| 536 | { | |||
| 537 | char *attic_name; | |||
| 538 | ||||
| 539 | attic_name = xmalloc (strlen (repository) + strlen (vfile) + | |||
| 540 | sizeof (CVSATTIC"Attic") + sizeof (RCSEXT",v") + 10); | |||
| 541 | (void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC"Attic", | |||
| 542 | vfile, RCSEXT",v"); | |||
| 543 | if (!isfile (attic_name)) | |||
| 544 | { | |||
| 545 | int retval; | |||
| 546 | char *free_opt = NULL((void*)0); | |||
| 547 | char *our_opt = keyword_opt; | |||
| 548 | ||||
| 549 | free (attic_name); | |||
| 550 | /* | |||
| 551 | * A new import source file; it doesn't exist as a ,v within the | |||
| 552 | * repository nor in the Attic -- create it anew. | |||
| 553 | */ | |||
| 554 | add_log ('N', vfile); | |||
| 555 | ||||
| 556 | #ifdef SERVER_SUPPORT1 | |||
| 557 | /* The most reliable information on whether the file is binary | |||
| 558 | is what the client told us. That is because if the client had | |||
| 559 | the wrong idea about binaryness, it corrupted the file, so | |||
| 560 | we might as well believe the client. */ | |||
| 561 | if (server_active) | |||
| 562 | { | |||
| 563 | Node *node; | |||
| 564 | List *entries; | |||
| 565 | ||||
| 566 | /* Reading all the entries for each file is fairly silly, and | |||
| 567 | probably slow. But I am too lazy at the moment to do | |||
| 568 | anything else. */ | |||
| 569 | entries = Entries_Open (0, NULL((void*)0)); | |||
| 570 | node = findnode_fn (entries, vfile); | |||
| 571 | if (node != NULL((void*)0)) | |||
| 572 | { | |||
| 573 | Entnode *entdata = (Entnode *) node->data; | |||
| 574 | if (entdata->type == ENT_FILE) | |||
| 575 | { | |||
| 576 | assert (entdata->options[0] == '-'((entdata->options[0] == '-' && entdata->options [1] == 'k') ? (void)0 : __assert2("/usr/src/gnu/usr.bin/cvs/src/import.c" , 577, __func__, "entdata->options[0] == '-' && entdata->options[1] == 'k'" )) | |||
| 577 | && entdata->options[1] == 'k')((entdata->options[0] == '-' && entdata->options [1] == 'k') ? (void)0 : __assert2("/usr/src/gnu/usr.bin/cvs/src/import.c" , 577, __func__, "entdata->options[0] == '-' && entdata->options[1] == 'k'" )); | |||
| 578 | our_opt = xstrdup (entdata->options + 2); | |||
| 579 | free_opt = our_opt; | |||
| 580 | } | |||
| 581 | } | |||
| 582 | Entries_Close (entries); | |||
| 583 | } | |||
| 584 | #endif | |||
| 585 | ||||
| 586 | retval = add_rcs_file (message, rcs, vfile, vhead, our_opt, | |||
| 587 | vbranch, vtag, targc, targv, | |||
| 588 | NULL((void*)0), 0, logfp); | |||
| 589 | if (free_opt != NULL((void*)0)) | |||
| 590 | free (free_opt); | |||
| 591 | free (rcs); | |||
| 592 | return retval; | |||
| 593 | } | |||
| 594 | free (attic_name); | |||
| 595 | inattic = 1; | |||
| 596 | } | |||
| 597 | ||||
| 598 | free (rcs); | |||
| 599 | /* | |||
| 600 | * an rcs file exists. have to do things the official, slow, way. | |||
| 601 | */ | |||
| 602 | return (update_rcs_file (message, vfile, vtag, targc, targv, inattic)); | |||
| 603 | } | |||
| 604 | ||||
| 605 | /* | |||
| 606 | * The RCS file exists; update it by adding the new import file to the | |||
| 607 | * (possibly already existing) vendor branch. | |||
| 608 | */ | |||
| 609 | static int | |||
| 610 | update_rcs_file (message, vfile, vtag, targc, targv, inattic) | |||
| 611 | char *message; | |||
| 612 | char *vfile; | |||
| 613 | char *vtag; | |||
| 614 | int targc; | |||
| 615 | char *targv[]; | |||
| 616 | int inattic; | |||
| 617 | { | |||
| 618 | Vers_TS *vers; | |||
| 619 | int letter; | |||
| 620 | char *tocvsPath; | |||
| 621 | struct file_info finfo; | |||
| 622 | ||||
| 623 | memset (&finfo, 0, sizeof finfo); | |||
| 624 | finfo.file = vfile; | |||
| 625 | /* Not used, so don't worry about it. */ | |||
| 626 | finfo.update_dir = NULL((void*)0); | |||
| 627 | finfo.fullname = finfo.file; | |||
| 628 | finfo.repository = repository; | |||
| 629 | finfo.entries = NULL((void*)0); | |||
| 630 | finfo.rcs = NULL((void*)0); | |||
| 631 | vers = Version_TS (&finfo, (char *) NULL((void*)0), vbranch, (char *) NULL((void*)0), | |||
| 632 | 1, 0); | |||
| 633 | if (vers->vn_rcs != NULL((void*)0) | |||
| 634 | && !RCS_isdead(vers->srcfile, vers->vn_rcs)) | |||
| 635 | { | |||
| 636 | int different; | |||
| 637 | ||||
| 638 | /* | |||
| 639 | * The rcs file does have a revision on the vendor branch. Compare | |||
| 640 | * this revision with the import file; if they match exactly, there | |||
| 641 | * is no need to install the new import file as a new revision to the | |||
| 642 | * branch. Just tag the revision with the new import tags. | |||
| 643 | * | |||
| 644 | * This is to try to cut down the number of "C" conflict messages for | |||
| 645 | * locally modified import source files. | |||
| 646 | */ | |||
| 647 | tocvsPath = wrap_tocvs_process_file (vfile); | |||
| 648 | /* FIXME: Why don't we pass tocvsPath to RCS_cmp_file if it is | |||
| 649 | not NULL? */ | |||
| 650 | different = RCS_cmp_file (vers->srcfile, vers->vn_rcs, "-ko", vfile); | |||
| 651 | if (tocvsPath) | |||
| 652 | if (unlink_file_dir (tocvsPath) < 0) | |||
| 653 | error (0, errno(*__errno()), "cannot remove %s", tocvsPath); | |||
| 654 | ||||
| 655 | if (!different) | |||
| 656 | { | |||
| 657 | int retval = 0; | |||
| 658 | ||||
| 659 | /* | |||
| 660 | * The two files are identical. Just update the tags, print the | |||
| 661 | * "U", signifying that the file has changed, but needs no | |||
| 662 | * attention, and we're done. | |||
| 663 | */ | |||
| 664 | if (add_tags (vers->srcfile, vfile, vtag, targc, targv)) | |||
| 665 | retval = 1; | |||
| 666 | add_log ('U', vfile); | |||
| 667 | freevers_ts (&vers); | |||
| 668 | return (retval); | |||
| 669 | } | |||
| 670 | } | |||
| 671 | ||||
| 672 | /* We may have failed to parse the RCS file; check just in case */ | |||
| 673 | if (vers->srcfile == NULL((void*)0) || | |||
| 674 | add_rev (message, vers->srcfile, vfile, vers->vn_rcs) || | |||
| 675 | add_tags (vers->srcfile, vfile, vtag, targc, targv)) | |||
| 676 | { | |||
| 677 | freevers_ts (&vers); | |||
| 678 | return (1); | |||
| 679 | } | |||
| 680 | ||||
| 681 | if (vers->srcfile->branch == NULL((void*)0) || inattic || | |||
| 682 | strcmp (vers->srcfile->branch, vbranch) != 0) | |||
| 683 | { | |||
| 684 | conflicts++; | |||
| 685 | letter = 'C'; | |||
| 686 | } | |||
| 687 | else | |||
| 688 | letter = 'U'; | |||
| 689 | add_log (letter, vfile); | |||
| 690 | ||||
| 691 | freevers_ts (&vers); | |||
| 692 | return (0); | |||
| 693 | } | |||
| 694 | ||||
| 695 | /* | |||
| 696 | * Add the revision to the vendor branch | |||
| 697 | */ | |||
| 698 | static int | |||
| 699 | add_rev (message, rcs, vfile, vers) | |||
| 700 | char *message; | |||
| 701 | RCSNode *rcs; | |||
| 702 | char *vfile; | |||
| 703 | char *vers; | |||
| 704 | { | |||
| 705 | int locked, status, ierrno; | |||
| 706 | char *tocvsPath; | |||
| 707 | ||||
| 708 | if (noexec) | |||
| 709 | return (0); | |||
| 710 | ||||
| 711 | locked = 0; | |||
| 712 | if (vers != NULL((void*)0)) | |||
| 713 | { | |||
| 714 | /* Before RCS_lock existed, we were directing stdout, as well as | |||
| 715 | stderr, from the RCS command, to DEVNULL. I wouldn't guess that | |||
| 716 | was necessary, but I don't know for sure. */ | |||
| 717 | /* Earlier versions of this function printed a `fork failed' error | |||
| 718 | when RCS_lock returned an error code. That's not appropriate | |||
| 719 | now that RCS_lock is librarified, but should the error text be | |||
| 720 | preserved? */ | |||
| 721 | if (RCS_lock (rcs, vbranch, 1) != 0) | |||
| 722 | return 1; | |||
| 723 | locked = 1; | |||
| 724 | RCS_rewrite (rcs, NULL((void*)0), NULL((void*)0)); | |||
| 725 | } | |||
| 726 | tocvsPath = wrap_tocvs_process_file (vfile); | |||
| 727 | ||||
| 728 | status = RCS_checkin (rcs, tocvsPath == NULL((void*)0) ? vfile : tocvsPath, | |||
| 729 | message, vbranch, | |||
| 730 | (RCS_FLAGS_QUIET4 | RCS_FLAGS_KEEPFILE16 | |||
| 731 | | (use_file_modtime ? RCS_FLAGS_MODTIME8 : 0))); | |||
| 732 | ierrno = errno(*__errno()); | |||
| 733 | ||||
| 734 | if ((tocvsPath != NULL((void*)0)) && (unlink_file_dir (tocvsPath) < 0)) | |||
| 735 | error (0, errno(*__errno()), "cannot remove %s", tocvsPath); | |||
| 736 | ||||
| 737 | if (status) | |||
| 738 | { | |||
| 739 | if (!noexec) | |||
| 740 | { | |||
| 741 | fperrmsg (logfp, 0, status == -1 ? ierrno : 0, | |||
| 742 | "ERROR: Check-in of %s failed", rcs->path); | |||
| 743 | error (0, status == -1 ? ierrno : 0, | |||
| 744 | "ERROR: Check-in of %s failed", rcs->path); | |||
| 745 | } | |||
| 746 | if (locked) | |||
| 747 | { | |||
| 748 | (void) RCS_unlock(rcs, vbranch, 0); | |||
| 749 | RCS_rewrite (rcs, NULL((void*)0), NULL((void*)0)); | |||
| 750 | } | |||
| 751 | return (1); | |||
| 752 | } | |||
| 753 | return (0); | |||
| 754 | } | |||
| 755 | ||||
| 756 | /* | |||
| 757 | * Add the vendor branch tag and all the specified import release tags to the | |||
| 758 | * RCS file. The vendor branch tag goes on the branch root (1.1.1) while the | |||
| 759 | * vendor release tags go on the newly added leaf of the branch (1.1.1.1, | |||
| 760 | * 1.1.1.2, ...). | |||
| 761 | */ | |||
| 762 | static int | |||
| 763 | add_tags (rcs, vfile, vtag, targc, targv) | |||
| 764 | RCSNode *rcs; | |||
| 765 | char *vfile; | |||
| 766 | char *vtag; | |||
| 767 | int targc; | |||
| 768 | char *targv[]; | |||
| 769 | { | |||
| 770 | int i, ierrno; | |||
| 771 | Vers_TS *vers; | |||
| 772 | int retcode = 0; | |||
| 773 | struct file_info finfo; | |||
| 774 | ||||
| 775 | if (noexec) | |||
| 776 | return (0); | |||
| 777 | ||||
| 778 | if ((retcode = RCS_settag(rcs, vtag, vbranch)) != 0) | |||
| 779 | { | |||
| 780 | ierrno = errno(*__errno()); | |||
| 781 | fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0, | |||
| 782 | "ERROR: Failed to set tag %s in %s", vtag, rcs->path); | |||
| 783 | error (0, retcode == -1 ? ierrno : 0, | |||
| 784 | "ERROR: Failed to set tag %s in %s", vtag, rcs->path); | |||
| 785 | return (1); | |||
| 786 | } | |||
| 787 | RCS_rewrite (rcs, NULL((void*)0), NULL((void*)0)); | |||
| 788 | ||||
| 789 | memset (&finfo, 0, sizeof finfo); | |||
| 790 | finfo.file = vfile; | |||
| 791 | /* Not used, so don't worry about it. */ | |||
| 792 | finfo.update_dir = NULL((void*)0); | |||
| 793 | finfo.fullname = finfo.file; | |||
| 794 | finfo.repository = repository; | |||
| 795 | finfo.entries = NULL((void*)0); | |||
| 796 | finfo.rcs = NULL((void*)0); | |||
| 797 | vers = Version_TS (&finfo, NULL((void*)0), vtag, NULL((void*)0), 1, 0); | |||
| 798 | for (i = 0; i < targc; i++) | |||
| 799 | { | |||
| 800 | if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) == 0) | |||
| 801 | RCS_rewrite (rcs, NULL((void*)0), NULL((void*)0)); | |||
| 802 | else | |||
| 803 | { | |||
| 804 | ierrno = errno(*__errno()); | |||
| 805 | fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0, | |||
| 806 | "WARNING: Couldn't add tag %s to %s", targv[i], | |||
| 807 | rcs->path); | |||
| 808 | error (0, retcode == -1 ? ierrno : 0, | |||
| 809 | "WARNING: Couldn't add tag %s to %s", targv[i], | |||
| 810 | rcs->path); | |||
| 811 | } | |||
| 812 | } | |||
| 813 | freevers_ts (&vers); | |||
| 814 | return (0); | |||
| 815 | } | |||
| 816 | ||||
| 817 | /* | |||
| 818 | * Stolen from rcs/src/rcsfnms.c, and adapted/extended. | |||
| 819 | */ | |||
| 820 | struct compair | |||
| 821 | { | |||
| 822 | char *suffix, *comlead; | |||
| 823 | }; | |||
| 824 | ||||
| 825 | static const struct compair comtable[] = | |||
| 826 | { | |||
| 827 | ||||
| 828 | /* | |||
| 829 | * comtable pairs each filename suffix with a comment leader. The comment | |||
| 830 | * leader is placed before each line generated by the $Log keyword. This | |||
| 831 | * table is used to guess the proper comment leader from the working file's | |||
| 832 | * suffix during initial ci (see InitAdmin()). Comment leaders are needed for | |||
| 833 | * languages without multiline comments; for others they are optional. | |||
| 834 | * | |||
| 835 | * I believe that the comment leader is unused if you are using RCS 5.7, which | |||
| 836 | * decides what leader to use based on the text surrounding the $Log keyword | |||
| 837 | * rather than a specified comment leader. | |||
| 838 | */ | |||
| 839 | {"a", "-- "}, /* Ada */ | |||
| 840 | {"ada", "-- "}, | |||
| 841 | {"adb", "-- "}, | |||
| 842 | {"asm", ";; "}, /* assembler (MS-DOS) */ | |||
| 843 | {"ads", "-- "}, /* Ada */ | |||
| 844 | {"bas", "' "}, /* Visual Basic code */ | |||
| 845 | {"bat", ":: "}, /* batch (MS-DOS) */ | |||
| 846 | {"body", "-- "}, /* Ada */ | |||
| 847 | {"c", " * "}, /* C */ | |||
| 848 | {"c++", "// "}, /* C++ in all its infinite guises */ | |||
| 849 | {"cc", "// "}, | |||
| 850 | {"cpp", "// "}, | |||
| 851 | {"cxx", "// "}, | |||
| 852 | {"m", "// "}, /* Objective-C */ | |||
| 853 | {"cl", ";;; "}, /* Common Lisp */ | |||
| 854 | {"cmd", ":: "}, /* command (OS/2) */ | |||
| 855 | {"cmf", "c "}, /* CM Fortran */ | |||
| 856 | {"cs", " * "}, /* C* */ | |||
| 857 | {"csh", "# "}, /* shell */ | |||
| 858 | {"dlg", " * "}, /* MS Windows dialog file */ | |||
| 859 | {"e", "# "}, /* efl */ | |||
| 860 | {"epsf", "% "}, /* encapsulated postscript */ | |||
| 861 | {"epsi", "% "}, /* encapsulated postscript */ | |||
| 862 | {"el", "; "}, /* Emacs Lisp */ | |||
| 863 | {"f", "c "}, /* Fortran */ | |||
| 864 | {"for", "c "}, | |||
| 865 | {"frm", "' "}, /* Visual Basic form */ | |||
| 866 | {"h", " * "}, /* C-header */ | |||
| 867 | {"hh", "// "}, /* C++ header */ | |||
| 868 | {"hpp", "// "}, | |||
| 869 | {"hxx", "// "}, | |||
| 870 | {"in", "# "}, /* for Makefile.in */ | |||
| 871 | {"l", " * "}, /* lex (conflict between lex and | |||
| 872 | * franzlisp) */ | |||
| 873 | {"mac", ";; "}, /* macro (DEC-10, MS-DOS, PDP-11, | |||
| 874 | * VMS, etc) */ | |||
| 875 | {"mak", "# "}, /* makefile, e.g. Visual C++ */ | |||
| 876 | {"me", ".\\\" "}, /* me-macros t/nroff */ | |||
| 877 | {"ml", "; "}, /* mocklisp */ | |||
| 878 | {"mm", ".\\\" "}, /* mm-macros t/nroff */ | |||
| 879 | {"ms", ".\\\" "}, /* ms-macros t/nroff */ | |||
| 880 | {"man", ".\\\" "}, /* man-macros t/nroff */ | |||
| 881 | {"1", ".\\\" "}, /* feeble attempt at man pages... */ | |||
| 882 | {"2", ".\\\" "}, | |||
| 883 | {"3", ".\\\" "}, | |||
| 884 | {"4", ".\\\" "}, | |||
| 885 | {"5", ".\\\" "}, | |||
| 886 | {"6", ".\\\" "}, | |||
| 887 | {"7", ".\\\" "}, | |||
| 888 | {"8", ".\\\" "}, | |||
| 889 | {"9", ".\\\" "}, | |||
| 890 | {"p", " * "}, /* pascal */ | |||
| 891 | {"pas", " * "}, | |||
| 892 | {"pl", "# "}, /* perl (conflict with Prolog) */ | |||
| 893 | {"ps", "% "}, /* postscript */ | |||
| 894 | {"psw", "% "}, /* postscript wrap */ | |||
| 895 | {"pswm", "% "}, /* postscript wrap */ | |||
| 896 | {"r", "# "}, /* ratfor */ | |||
| 897 | {"rc", " * "}, /* Microsoft Windows resource file */ | |||
| 898 | {"red", "% "}, /* psl/rlisp */ | |||
| 899 | #ifdef __sparc__ | |||
| 900 | {"s", "! "}, /* assembler */ | |||
| 901 | #endif | |||
| 902 | #ifdef __sparc64__ | |||
| 903 | {"s", "! "}, /* assembler */ | |||
| 904 | #endif | |||
| 905 | #ifdef __mc68000__ | |||
| 906 | {"s", "| "}, /* assembler */ | |||
| 907 | #endif | |||
| 908 | #ifdef __pdp11__ | |||
| 909 | {"s", "/ "}, /* assembler */ | |||
| 910 | #endif | |||
| 911 | #ifdef __vax__ | |||
| 912 | {"s", "# "}, /* assembler */ | |||
| 913 | #endif | |||
| 914 | #ifdef __ksr__ | |||
| 915 | {"s", "# "}, /* assembler */ | |||
| 916 | {"S", "# "}, /* Macro assembler */ | |||
| 917 | #endif | |||
| 918 | {"sh", "# "}, /* shell */ | |||
| 919 | {"sl", "% "}, /* psl */ | |||
| 920 | {"spec", "-- "}, /* Ada */ | |||
| 921 | {"tex", "% "}, /* tex */ | |||
| 922 | {"y", " * "}, /* yacc */ | |||
| 923 | {"ye", " * "}, /* yacc-efl */ | |||
| 924 | {"yr", " * "}, /* yacc-ratfor */ | |||
| 925 | {"", "# "}, /* default for empty suffix */ | |||
| 926 | {NULL((void*)0), "# "} /* default for unknown suffix; */ | |||
| 927 | /* must always be last */ | |||
| 928 | }; | |||
| 929 | ||||
| 930 | static char * | |||
| 931 | get_comment (user) | |||
| 932 | char *user; | |||
| 933 | { | |||
| 934 | char *cp, *suffix; | |||
| 935 | char *suffix_path; | |||
| 936 | int i; | |||
| 937 | char *retval; | |||
| 938 | ||||
| 939 | suffix_path = xmalloc (strlen (user) + 5); | |||
| 940 | cp = strrchr (user, '.'); | |||
| 941 | if (cp != NULL((void*)0)) | |||
| 942 | { | |||
| 943 | cp++; | |||
| 944 | ||||
| 945 | /* | |||
| 946 | * Convert to lower-case, since we are not concerned about the | |||
| 947 | * case-ness of the suffix. | |||
| 948 | */ | |||
| 949 | (void) strcpy (suffix_path, cp); | |||
| 950 | for (cp = suffix_path; *cp; cp++) | |||
| 951 | if (isupper ((unsigned char) *cp)) | |||
| 952 | *cp = tolower (*cp); | |||
| 953 | suffix = suffix_path; | |||
| 954 | } | |||
| 955 | else | |||
| 956 | suffix = ""; /* will use the default */ | |||
| 957 | for (i = 0;; i++) | |||
| 958 | { | |||
| 959 | if (comtable[i].suffix == NULL((void*)0)) | |||
| 960 | { | |||
| 961 | /* Default. Note we'll always hit this case before we | |||
| 962 | ever return NULL. */ | |||
| 963 | retval = comtable[i].comlead; | |||
| 964 | break; | |||
| 965 | } | |||
| 966 | if (strcmp (suffix, comtable[i].suffix) == 0) | |||
| 967 | { | |||
| 968 | retval = comtable[i].comlead; | |||
| 969 | break; | |||
| 970 | } | |||
| 971 | } | |||
| 972 | free (suffix_path); | |||
| 973 | return retval; | |||
| 974 | } | |||
| 975 | ||||
| 976 | /* Create a new RCS file from scratch. | |||
| 977 | ||||
| 978 | This probably should be moved to rcs.c now that it is called from | |||
| 979 | places outside import.c. | |||
| 980 | ||||
| 981 | Return value is 0 for success, or nonzero for failure (in which | |||
| 982 | case an error message will have already been printed). */ | |||
| 983 | int | |||
| 984 | add_rcs_file (message, rcs, user, add_vhead, key_opt, | |||
| 985 | add_vbranch, vtag, targc, targv, | |||
| 986 | desctext, desclen, add_logfp) | |||
| 987 | /* Log message for the addition. Not used if add_vhead == NULL. */ | |||
| 988 | char *message; | |||
| 989 | /* Filename of the RCS file to create. */ | |||
| 990 | char *rcs; | |||
| 991 | /* Filename of the file to serve as the contents of the initial | |||
| 992 | revision. Even if add_vhead is NULL, we use this to determine | |||
| 993 | the modes to give the new RCS file. */ | |||
| 994 | char *user; | |||
| 995 | ||||
| 996 | /* Revision number of head that we are adding. Normally 1.1 but | |||
| 997 | could be another revision as long as ADD_VBRANCH is a branch | |||
| 998 | from it. If NULL, then just add an empty file without any | |||
| 999 | revisions (similar to the one created by "rcs -i"). */ | |||
| 1000 | char *add_vhead; | |||
| 1001 | ||||
| 1002 | /* Keyword expansion mode, e.g., "b" for binary. NULL means the | |||
| 1003 | default behavior. */ | |||
| 1004 | char *key_opt; | |||
| 1005 | ||||
| 1006 | /* Vendor branch to import to, or NULL if none. If non-NULL, then | |||
| 1007 | vtag should also be non-NULL. */ | |||
| 1008 | char *add_vbranch; | |||
| 1009 | char *vtag; | |||
| 1010 | int targc; | |||
| 1011 | char *targv[]; | |||
| 1012 | ||||
| 1013 | /* If non-NULL, description for the file. If NULL, the description | |||
| 1014 | will be empty. */ | |||
| 1015 | char *desctext; | |||
| 1016 | size_t desclen; | |||
| 1017 | ||||
| 1018 | /* Write errors to here as well as via error (), or NULL if we should | |||
| 1019 | use only error (). */ | |||
| 1020 | FILE *add_logfp; | |||
| 1021 | { | |||
| 1022 | FILE *fprcs, *fpuser; | |||
| 1023 | struct stat sb; | |||
| 1024 | struct tm *ftm; | |||
| 1025 | time_t now; | |||
| 1026 | char altdate1[MAXDATELEN50]; | |||
| 1027 | char *author; | |||
| 1028 | int i, ierrno, err = 0; | |||
| 1029 | mode_t mode; | |||
| 1030 | char *tocvsPath; | |||
| 1031 | char *userfile; | |||
| 1032 | char *local_opt = key_opt; | |||
| 1033 | char *free_opt = NULL((void*)0); | |||
| 1034 | mode_t file_type; | |||
| 1035 | ||||
| 1036 | if (noexec) | |||
| ||||
| 1037 | return (0); | |||
| 1038 | ||||
| 1039 | /* Note that as the code stands now, the -k option overrides any | |||
| 1040 | settings in wrappers (whether CVSROOT/cvswrappers, -W, or | |||
| 1041 | whatever). Some have suggested this should be the other way | |||
| 1042 | around. As far as I know the documentation doesn't say one way | |||
| 1043 | or the other. Before making a change of this sort, should think | |||
| 1044 | about what is best, document it (in cvs.texinfo and NEWS), &c. */ | |||
| 1045 | ||||
| 1046 | if (local_opt == NULL((void*)0)) | |||
| 1047 | { | |||
| 1048 | if (wrap_name_has (user, WRAP_RCSOPTION)) | |||
| 1049 | { | |||
| 1050 | local_opt = free_opt = wrap_rcsoption (user, 0); | |||
| 1051 | } | |||
| 1052 | } | |||
| 1053 | ||||
| 1054 | tocvsPath = wrap_tocvs_process_file (user); | |||
| 1055 | userfile = (tocvsPath == NULL((void*)0) ? user : tocvsPath); | |||
| 1056 | ||||
| 1057 | /* Opening in text mode is probably never the right thing for the | |||
| 1058 | server (because the protocol encodes text files in a fashion | |||
| 1059 | which does not depend on what the client or server OS is, as | |||
| 1060 | documented in cvsclient.texi), but as long as the server just | |||
| 1061 | runs on unix it is a moot point. */ | |||
| 1062 | ||||
| 1063 | /* If PreservePermissions is set, then make sure that the file | |||
| 1064 | is a plain file before trying to open it. Longstanding (although | |||
| 1065 | often unpopular) CVS behavior has been to follow symlinks, so we | |||
| 1066 | maintain that behavior if PreservePermissions is not on. | |||
| 1067 | ||||
| 1068 | NOTE: this error message used to be `cannot fstat', but is now | |||
| 1069 | `cannot lstat'. I don't see a way around this, since we must | |||
| 1070 | stat the file before opening it. -twp */ | |||
| 1071 | ||||
| 1072 | if (CVS_LSTATlstat (userfile, &sb) < 0) | |||
| 1073 | { | |||
| 1074 | /* not fatal, continue import */ | |||
| 1075 | if (add_logfp != NULL((void*)0)) | |||
| 1076 | fperrmsg (add_logfp, 0, errno(*__errno()), | |||
| 1077 | "ERROR: cannot lstat file %s", userfile); | |||
| 1078 | error (0, errno(*__errno()), "cannot lstat file %s", userfile); | |||
| 1079 | goto read_error; | |||
| 1080 | } | |||
| 1081 | file_type = sb.st_mode & S_IFMT0170000; | |||
| 1082 | ||||
| 1083 | fpuser = NULL((void*)0); | |||
| 1084 | if (!preserve_perms || file_type == S_IFREG0100000) | |||
| 1085 | { | |||
| 1086 | fpuser = CVS_FOPENfopen (userfile, | |||
| 1087 | ((local_opt != NULL((void*)0) && strcmp (local_opt, "b") == 0) | |||
| 1088 | ? "rb" | |||
| 1089 | : "r") | |||
| 1090 | ); | |||
| 1091 | if (fpuser == NULL((void*)0)) | |||
| 1092 | { | |||
| 1093 | /* not fatal, continue import */ | |||
| 1094 | if (add_logfp != NULL((void*)0)) | |||
| 1095 | fperrmsg (add_logfp, 0, errno(*__errno()), | |||
| 1096 | "ERROR: cannot read file %s", userfile); | |||
| 1097 | error (0, errno(*__errno()), "ERROR: cannot read file %s", userfile); | |||
| 1098 | goto read_error; | |||
| 1099 | } | |||
| 1100 | } | |||
| 1101 | ||||
| 1102 | fprcs = CVS_FOPENfopen (rcs, "w+b"); | |||
| 1103 | if (fprcs == NULL((void*)0)) | |||
| 1104 | { | |||
| 1105 | ierrno = errno(*__errno()); | |||
| 1106 | goto write_error_noclose; | |||
| 1107 | } | |||
| 1108 | ||||
| 1109 | /* | |||
| 1110 | * putadmin() | |||
| 1111 | */ | |||
| 1112 | if (add_vhead != NULL((void*)0)) | |||
| 1113 | { | |||
| 1114 | if (fprintf (fprcs, "head %s;\012", add_vhead) < 0) | |||
| 1115 | goto write_error; | |||
| 1116 | } | |||
| 1117 | else | |||
| 1118 | { | |||
| 1119 | if (fprintf (fprcs, "head ;\012") < 0) | |||
| 1120 | goto write_error; | |||
| 1121 | } | |||
| 1122 | ||||
| 1123 | if (add_vbranch != NULL((void*)0)) | |||
| 1124 | { | |||
| 1125 | if (fprintf (fprcs, "branch %s;\012", add_vbranch) < 0) | |||
| 1126 | goto write_error; | |||
| 1127 | } | |||
| 1128 | if (fprintf (fprcs, "access ;\012") < 0 || | |||
| 1129 | fprintf (fprcs, "symbols ") < 0) | |||
| 1130 | { | |||
| 1131 | goto write_error; | |||
| 1132 | } | |||
| 1133 | ||||
| 1134 | for (i = targc - 1; i >= 0; i--) | |||
| 1135 | { | |||
| 1136 | /* RCS writes the symbols backwards */ | |||
| 1137 | assert (add_vbranch != NULL)((add_vbranch != ((void*)0)) ? (void)0 : __assert2("/usr/src/gnu/usr.bin/cvs/src/import.c" , 1137, __func__, "add_vbranch != NULL")); | |||
| 1138 | if (fprintf (fprcs, "%s:%s.1 ", targv[i], add_vbranch) < 0) | |||
| 1139 | goto write_error; | |||
| 1140 | } | |||
| 1141 | ||||
| 1142 | if (add_vbranch
| |||
| 1143 | { | |||
| 1144 | if (fprintf (fprcs, "%s:%s", vtag, add_vbranch) < 0) | |||
| 1145 | goto write_error; | |||
| 1146 | } | |||
| 1147 | if (fprintf (fprcs, ";\012") < 0) | |||
| 1148 | goto write_error; | |||
| 1149 | ||||
| 1150 | if (fprintf (fprcs, "locks ; strict;\012") < 0 || | |||
| 1151 | /* XXX - make sure @@ processing works in the RCS file */ | |||
| 1152 | fprintf (fprcs, "comment @%s@;\012", get_comment (user)) < 0) | |||
| 1153 | { | |||
| 1154 | goto write_error; | |||
| 1155 | } | |||
| 1156 | ||||
| 1157 | if (local_opt
| |||
| 1158 | { | |||
| 1159 | if (fprintf (fprcs, "expand @%s@;\012", local_opt) < 0) | |||
| 1160 | { | |||
| 1161 | goto write_error; | |||
| 1162 | } | |||
| 1163 | } | |||
| 1164 | ||||
| 1165 | if (fprintf (fprcs, "\012") < 0) | |||
| 1166 | goto write_error; | |||
| 1167 | ||||
| 1168 | /* Write the revision(s), with the date and author and so on | |||
| 1169 | (that is "delta" rather than "deltatext" from rcsfile(5)). */ | |||
| 1170 | if (add_vhead
| |||
| 1171 | { | |||
| 1172 | if (use_file_modtime) | |||
| 1173 | now = sb.st_mtimest_mtim.tv_sec; | |||
| 1174 | else | |||
| 1175 | (void) time (&now); | |||
| 1176 | ftm = gmtime (&now); | |||
| 1177 | (void) sprintf (altdate1, DATEFORM"%02d.%02d.%02d.%02d.%02d.%02d", | |||
| 1178 | ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), | |||
| 1179 | ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, | |||
| 1180 | ftm->tm_min, ftm->tm_sec); | |||
| 1181 | author = getcaller (); | |||
| 1182 | ||||
| 1183 | if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 || | |||
| 1184 | fprintf (fprcs, "date %s; author %s; state Exp;\012", | |||
| 1185 | altdate1, author) < 0) | |||
| 1186 | goto write_error; | |||
| 1187 | ||||
| 1188 | if (fprintf (fprcs, "branches") < 0) | |||
| 1189 | goto write_error; | |||
| 1190 | if (add_vbranch
| |||
| 1191 | { | |||
| 1192 | if (fprintf (fprcs, " %s.1", add_vbranch) < 0) | |||
| 1193 | goto write_error; | |||
| 1194 | } | |||
| 1195 | if (fprintf (fprcs, ";\012") < 0) | |||
| 1196 | goto write_error; | |||
| 1197 | ||||
| 1198 | if (fprintf (fprcs, "next ;\012") < 0) | |||
| 1199 | goto write_error; | |||
| 1200 | ||||
| 1201 | if (fprintf (fprcs, "commitid %s;\012", global_session_id) < 0) | |||
| 1202 | goto write_error; | |||
| 1203 | ||||
| 1204 | #ifdef PRESERVE_PERMISSIONS_SUPPORT | |||
| 1205 | /* Store initial permissions if necessary. */ | |||
| 1206 | if (preserve_perms) | |||
| 1207 | { | |||
| 1208 | if (file_type == S_IFLNK0120000) | |||
| 1209 | { | |||
| 1210 | char *link = xreadlink (userfile); | |||
| 1211 | if (fprintf (fprcs, "symlink\t@") < 0 || | |||
| 1212 | expand_at_signs (link, strlen (link), fprcs) < 0 || | |||
| 1213 | fprintf (fprcs, "@;\012") < 0) | |||
| 1214 | goto write_error; | |||
| 1215 | free (link); | |||
| 1216 | } | |||
| 1217 | else | |||
| 1218 | { | |||
| 1219 | if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0) | |||
| 1220 | goto write_error; | |||
| 1221 | if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0) | |||
| 1222 | goto write_error; | |||
| 1223 | if (fprintf (fprcs, "permissions\t%o;\012", | |||
| 1224 | sb.st_mode & 07777) < 0) | |||
| 1225 | goto write_error; | |||
| 1226 | switch (file_type) | |||
| 1227 | { | |||
| 1228 | case S_IFREG0100000: break; | |||
| 1229 | case S_IFCHR0020000: | |||
| 1230 | case S_IFBLK0060000: | |||
| 1231 | #ifdef HAVE_ST_RDEV1 | |||
| 1232 | if (fprintf (fprcs, "special\t%s %lu;\012", | |||
| 1233 | (file_type == S_IFCHR0020000 | |||
| 1234 | ? "character" | |||
| 1235 | : "block"), | |||
| 1236 | (unsigned long) sb.st_rdev) < 0) | |||
| 1237 | goto write_error; | |||
| 1238 | #else | |||
| 1239 | error (0, 0, | |||
| 1240 | "can't import %s: unable to import device files on this system", | |||
| 1241 | userfile); | |||
| 1242 | #endif | |||
| 1243 | break; | |||
| 1244 | default: | |||
| 1245 | error (0, 0, | |||
| 1246 | "can't import %s: unknown kind of special file", | |||
| 1247 | userfile); | |||
| 1248 | } | |||
| 1249 | } | |||
| 1250 | } | |||
| 1251 | #endif | |||
| 1252 | ||||
| 1253 | if (add_vbranch
| |||
| 1254 | { | |||
| 1255 | if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 || | |||
| 1256 | fprintf (fprcs, "date %s; author %s; state Exp;\012", | |||
| 1257 | altdate1, author) < 0 || | |||
| 1258 | fprintf (fprcs, "branches ;\012") < 0 || | |||
| 1259 | fprintf (fprcs, "next ;\012") < 0 || | |||
| 1260 | fprintf (fprcs, "commitid %s;\012", global_session_id) < 0 | |||
| 1261 | ) | |||
| 1262 | goto write_error; | |||
| 1263 | ||||
| 1264 | #ifdef PRESERVE_PERMISSIONS_SUPPORT | |||
| 1265 | /* Store initial permissions if necessary. */ | |||
| 1266 | if (preserve_perms) | |||
| 1267 | { | |||
| 1268 | if (file_type == S_IFLNK0120000) | |||
| 1269 | { | |||
| 1270 | char *link = xreadlink (userfile); | |||
| 1271 | if (fprintf (fprcs, "symlink\t@") < 0 || | |||
| 1272 | expand_at_signs (link, strlen (link), fprcs) < 0 || | |||
| 1273 | fprintf (fprcs, "@;\012") < 0) | |||
| 1274 | goto write_error; | |||
| 1275 | free (link); | |||
| 1276 | } | |||
| 1277 | else | |||
| 1278 | { | |||
| 1279 | if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 || | |||
| 1280 | fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 || | |||
| 1281 | fprintf (fprcs, "permissions\t%o;\012", | |||
| 1282 | sb.st_mode & 07777) < 0) | |||
| 1283 | goto write_error; | |||
| 1284 | ||||
| 1285 | switch (file_type) | |||
| 1286 | { | |||
| 1287 | case S_IFREG0100000: break; | |||
| 1288 | case S_IFCHR0020000: | |||
| 1289 | case S_IFBLK0060000: | |||
| 1290 | #ifdef HAVE_ST_RDEV1 | |||
| 1291 | if (fprintf (fprcs, "special\t%s %lu;\012", | |||
| 1292 | (file_type == S_IFCHR0020000 | |||
| 1293 | ? "character" | |||
| 1294 | : "block"), | |||
| 1295 | (unsigned long) sb.st_rdev) < 0) | |||
| 1296 | goto write_error; | |||
| 1297 | #else | |||
| 1298 | error (0, 0, | |||
| 1299 | "can't import %s: unable to import device files on this system", | |||
| 1300 | userfile); | |||
| 1301 | #endif | |||
| 1302 | break; | |||
| 1303 | default: | |||
| 1304 | error (0, 0, | |||
| 1305 | "cannot import %s: special file of unknown type", | |||
| 1306 | userfile); | |||
| 1307 | } | |||
| 1308 | } | |||
| 1309 | } | |||
| 1310 | #endif | |||
| 1311 | ||||
| 1312 | if (fprintf (fprcs, "\012") < 0) | |||
| 1313 | goto write_error; | |||
| 1314 | } | |||
| 1315 | } | |||
| 1316 | ||||
| 1317 | /* Now write the description (possibly empty). */ | |||
| 1318 | if (fprintf (fprcs, "\012desc\012") < 0 || | |||
| 1319 | fprintf (fprcs, "@") < 0) | |||
| 1320 | goto write_error; | |||
| 1321 | if (desctext != NULL((void*)0)) | |||
| 1322 | { | |||
| 1323 | /* The use of off_t not size_t for the second argument is very | |||
| 1324 | strange, since we are dealing with something which definitely | |||
| 1325 | fits in memory. */ | |||
| 1326 | if (expand_at_signs (desctext, (off_t) desclen, fprcs) < 0) | |||
| 1327 | goto write_error; | |||
| 1328 | } | |||
| 1329 | if (fprintf (fprcs, "@\012\012\012") < 0) | |||
| 1330 | goto write_error; | |||
| 1331 | ||||
| 1332 | /* Now write the log messages and contents for the revision(s) (that | |||
| 1333 | is, "deltatext" rather than "delta" from rcsfile(5)). */ | |||
| 1334 | if (add_vhead
| |||
| 1335 | { | |||
| 1336 | if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 || | |||
| 1337 | fprintf (fprcs, "log\012@") < 0) | |||
| 1338 | goto write_error; | |||
| 1339 | if (add_vbranch
| |||
| 1340 | { | |||
| 1341 | /* We are going to put the log message in the revision on the | |||
| 1342 | branch. So putting it here too seems kind of redundant, I | |||
| 1343 | guess (and that is what CVS has always done, anyway). */ | |||
| 1344 | if (fprintf (fprcs, "Initial revision\012") < 0) | |||
| 1345 | goto write_error; | |||
| 1346 | } | |||
| 1347 | else | |||
| 1348 | { | |||
| 1349 | if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0) | |||
| 1350 | goto write_error; | |||
| 1351 | } | |||
| 1352 | if (fprintf (fprcs, "@\012") < 0 || | |||
| 1353 | fprintf (fprcs, "text\012@") < 0) | |||
| 1354 | { | |||
| 1355 | goto write_error; | |||
| 1356 | } | |||
| 1357 | ||||
| 1358 | /* Now copy over the contents of the file, expanding at signs. | |||
| 1359 | If preserve_perms is set, do this only for regular files. */ | |||
| 1360 | if (!preserve_perms || file_type == S_IFREG0100000) | |||
| 1361 | { | |||
| 1362 | char buf[8192]; | |||
| 1363 | unsigned int len; | |||
| 1364 | ||||
| 1365 | while (1) | |||
| 1366 | { | |||
| 1367 | len = fread (buf, 1, sizeof buf, fpuser); | |||
| 1368 | if (len == 0) | |||
| 1369 | { | |||
| 1370 | if (ferror (fpuser)(!__isthreaded ? (((fpuser)->_flags & 0x0040) != 0) : ( ferror)(fpuser))) | |||
| ||||
| 1371 | error (1, errno(*__errno()), "cannot read file %s for copying", | |||
| 1372 | user); | |||
| 1373 | break; | |||
| 1374 | } | |||
| 1375 | if (expand_at_signs (buf, len, fprcs) < 0) | |||
| 1376 | goto write_error; | |||
| 1377 | } | |||
| 1378 | } | |||
| 1379 | if (fprintf (fprcs, "@\012\012") < 0) | |||
| 1380 | goto write_error; | |||
| 1381 | if (add_vbranch != NULL((void*)0)) | |||
| 1382 | { | |||
| 1383 | if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 || | |||
| 1384 | fprintf (fprcs, "log\012@") < 0 || | |||
| 1385 | expand_at_signs (message, | |||
| 1386 | (off_t) strlen (message), fprcs) < 0 || | |||
| 1387 | fprintf (fprcs, "@\012text\012") < 0 || | |||
| 1388 | fprintf (fprcs, "@@\012") < 0) | |||
| 1389 | goto write_error; | |||
| 1390 | } | |||
| 1391 | } | |||
| 1392 | ||||
| 1393 | if (fclose (fprcs) == EOF(-1)) | |||
| 1394 | { | |||
| 1395 | ierrno = errno(*__errno()); | |||
| 1396 | goto write_error_noclose; | |||
| 1397 | } | |||
| 1398 | /* Close fpuser only if we opened it to begin with. */ | |||
| 1399 | if (fpuser != NULL((void*)0)) | |||
| 1400 | { | |||
| 1401 | if (fclose (fpuser) < 0) | |||
| 1402 | error (0, errno(*__errno()), "cannot close %s", user); | |||
| 1403 | } | |||
| 1404 | ||||
| 1405 | /* | |||
| 1406 | * Fix the modes on the RCS files. The user modes of the original | |||
| 1407 | * user file are propagated to the group and other modes as allowed | |||
| 1408 | * by the repository umask, except that all write permissions are | |||
| 1409 | * turned off. | |||
| 1410 | */ | |||
| 1411 | mode = (sb.st_mode | | |||
| 1412 | (sb.st_mode & S_IRWXU0000700) >> 3 | | |||
| 1413 | (sb.st_mode & S_IRWXU0000700) >> 6) & | |||
| 1414 | ~cvsumask & | |||
| 1415 | ~(S_IWRITE0000200 | S_IWGRP0000020 | S_IWOTH0000002); | |||
| 1416 | if (chmod (rcs, mode) < 0) | |||
| 1417 | { | |||
| 1418 | ierrno = errno(*__errno()); | |||
| 1419 | if (add_logfp != NULL((void*)0)) | |||
| 1420 | fperrmsg (add_logfp, 0, ierrno, | |||
| 1421 | "WARNING: cannot change mode of file %s", rcs); | |||
| 1422 | error (0, ierrno, "WARNING: cannot change mode of file %s", rcs); | |||
| 1423 | err++; | |||
| 1424 | } | |||
| 1425 | if (tocvsPath) | |||
| 1426 | if (unlink_file_dir (tocvsPath) < 0) | |||
| 1427 | error (0, errno(*__errno()), "cannot remove %s", tocvsPath); | |||
| 1428 | if (free_opt != NULL((void*)0)) | |||
| 1429 | free (free_opt); | |||
| 1430 | return (err); | |||
| 1431 | ||||
| 1432 | write_error: | |||
| 1433 | ierrno = errno(*__errno()); | |||
| 1434 | if (fclose (fprcs) < 0) | |||
| 1435 | error (0, errno(*__errno()), "cannot close %s", rcs); | |||
| 1436 | write_error_noclose: | |||
| 1437 | if (fclose (fpuser) < 0) | |||
| 1438 | error (0, errno(*__errno()), "cannot close %s", user); | |||
| 1439 | if (add_logfp != NULL((void*)0)) | |||
| 1440 | fperrmsg (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs); | |||
| 1441 | error (0, ierrno, "ERROR: cannot write file %s", rcs); | |||
| 1442 | if (ierrno == ENOSPC28) | |||
| 1443 | { | |||
| 1444 | if (CVS_UNLINKunlink (rcs) < 0) | |||
| 1445 | error (0, errno(*__errno()), "cannot remove %s", rcs); | |||
| 1446 | if (add_logfp != NULL((void*)0)) | |||
| 1447 | fperrmsg (add_logfp, 0, 0, "ERROR: out of space - aborting"); | |||
| 1448 | error (1, 0, "ERROR: out of space - aborting"); | |||
| 1449 | } | |||
| 1450 | read_error: | |||
| 1451 | if (tocvsPath) | |||
| 1452 | if (unlink_file_dir (tocvsPath) < 0) | |||
| 1453 | error (0, errno(*__errno()), "cannot remove %s", tocvsPath); | |||
| 1454 | ||||
| 1455 | if (free_opt != NULL((void*)0)) | |||
| 1456 | free (free_opt); | |||
| 1457 | ||||
| 1458 | return (err + 1); | |||
| 1459 | } | |||
| 1460 | ||||
| 1461 | /* | |||
| 1462 | * Write SIZE bytes at BUF to FP, expanding @ signs into double @ | |||
| 1463 | * signs. If an error occurs, return a negative value and set errno | |||
| 1464 | * to indicate the error. If not, return a nonnegative value. | |||
| 1465 | */ | |||
| 1466 | int | |||
| 1467 | expand_at_signs (buf, size, fp) | |||
| 1468 | char *buf; | |||
| 1469 | off_t size; | |||
| 1470 | FILE *fp; | |||
| 1471 | { | |||
| 1472 | register char *cp, *next; | |||
| 1473 | ||||
| 1474 | cp = buf; | |||
| 1475 | while ((next = memchr (cp, '@', size)) != NULL((void*)0)) | |||
| 1476 | { | |||
| 1477 | int len; | |||
| 1478 | ||||
| 1479 | ++next; | |||
| 1480 | len = next - cp; | |||
| 1481 | if (fwrite (cp, 1, len, fp) != len) | |||
| 1482 | return EOF(-1); | |||
| 1483 | if (putc ('@', fp)(!__isthreaded ? __sputc('@', fp) : (putc)('@', fp)) == EOF(-1)) | |||
| 1484 | return EOF(-1); | |||
| 1485 | cp = next; | |||
| 1486 | size -= len; | |||
| 1487 | } | |||
| 1488 | ||||
| 1489 | if (fwrite (cp, 1, size, fp) != size) | |||
| 1490 | return EOF(-1); | |||
| 1491 | ||||
| 1492 | return 1; | |||
| 1493 | } | |||
| 1494 | ||||
| 1495 | /* | |||
| 1496 | * Write an update message to (potentially) the screen and the log file. | |||
| 1497 | */ | |||
| 1498 | static void | |||
| 1499 | add_log (ch, fname) | |||
| 1500 | int ch; | |||
| 1501 | char *fname; | |||
| 1502 | { | |||
| 1503 | if (!really_quiet) /* write to terminal */ | |||
| 1504 | { | |||
| 1505 | char buf[2]; | |||
| 1506 | buf[0] = ch; | |||
| 1507 | buf[1] = ' '; | |||
| 1508 | cvs_output (buf, 2); | |||
| 1509 | if (repos_len) | |||
| 1510 | { | |||
| 1511 | cvs_output (repository + repos_len + 1, 0); | |||
| 1512 | cvs_output ("/", 1); | |||
| 1513 | } | |||
| 1514 | else if (repository[0] != '\0') | |||
| 1515 | { | |||
| 1516 | cvs_output (repository, 0); | |||
| 1517 | cvs_output ("/", 1); | |||
| 1518 | } | |||
| 1519 | cvs_output (fname, 0); | |||
| 1520 | cvs_output ("\n", 1); | |||
| 1521 | } | |||
| 1522 | ||||
| 1523 | if (repos_len) /* write to logfile */ | |||
| 1524 | (void) fprintf (logfp, "%c %s/%s\n", ch, | |||
| 1525 | repository + repos_len + 1, fname); | |||
| 1526 | else if (repository[0]) | |||
| 1527 | (void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname); | |||
| 1528 | else | |||
| 1529 | (void) fprintf (logfp, "%c %s\n", ch, fname); | |||
| 1530 | } | |||
| 1531 | ||||
| 1532 | /* | |||
| 1533 | * This is the recursive function that walks the argument directory looking | |||
| 1534 | * for sub-directories that have CVS administration files in them and updates | |||
| 1535 | * them recursively. | |||
| 1536 | * | |||
| 1537 | * Note that we do not follow symbolic links here, which is a feature! | |||
| 1538 | */ | |||
| 1539 | static int | |||
| 1540 | import_descend_dir (message, dir, vtag, targc, targv) | |||
| 1541 | char *message; | |||
| 1542 | char *dir; | |||
| 1543 | char *vtag; | |||
| 1544 | int targc; | |||
| 1545 | char *targv[]; | |||
| 1546 | { | |||
| 1547 | struct saved_cwd cwd; | |||
| 1548 | char *cp; | |||
| 1549 | int ierrno, err; | |||
| 1550 | char *rcs = NULL((void*)0); | |||
| 1551 | ||||
| 1552 | if (islink (dir)) | |||
| 1553 | return (0); | |||
| 1554 | if (save_cwd (&cwd)) | |||
| 1555 | { | |||
| 1556 | fperrmsg (logfp, 0, 0, "ERROR: cannot get working directory"); | |||
| 1557 | return (1); | |||
| 1558 | } | |||
| 1559 | ||||
| 1560 | /* Concatenate DIR to the end of REPOSITORY. */ | |||
| 1561 | if (repository[0] == '\0') | |||
| 1562 | { | |||
| 1563 | char *new = xstrdup (dir); | |||
| 1564 | free (repository); | |||
| 1565 | repository = new; | |||
| 1566 | } | |||
| 1567 | else | |||
| 1568 | { | |||
| 1569 | char *new = xmalloc (strlen (repository) + strlen (dir) + 10); | |||
| 1570 | strcpy (new, repository); | |||
| 1571 | (void) strcat (new, "/"); | |||
| 1572 | (void) strcat (new, dir); | |||
| 1573 | free (repository); | |||
| 1574 | repository = new; | |||
| 1575 | } | |||
| 1576 | ||||
| 1577 | #ifdef CLIENT_SUPPORT1 | |||
| 1578 | if (!quiet && !current_parsed_root->isremote) | |||
| 1579 | #else | |||
| 1580 | if (!quiet) | |||
| 1581 | #endif | |||
| 1582 | error (0, 0, "Importing %s", repository); | |||
| 1583 | ||||
| 1584 | if ( CVS_CHDIRchdir (dir) < 0) | |||
| 1585 | { | |||
| 1586 | ierrno = errno(*__errno()); | |||
| 1587 | fperrmsg (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository); | |||
| 1588 | error (0, ierrno, "ERROR: cannot chdir to %s", repository); | |||
| 1589 | err = 1; | |||
| 1590 | goto out; | |||
| 1591 | } | |||
| 1592 | #ifdef CLIENT_SUPPORT1 | |||
| 1593 | if (!current_parsed_root->isremote && !isdir (repository)) | |||
| 1594 | #else | |||
| 1595 | if (!isdir (repository)) | |||
| 1596 | #endif | |||
| 1597 | { | |||
| 1598 | rcs = xmalloc (strlen (repository) + sizeof (RCSEXT",v") + 5); | |||
| 1599 | (void) sprintf (rcs, "%s%s", repository, RCSEXT",v"); | |||
| 1600 | if (isfile (repository) || isfile(rcs)) | |||
| 1601 | { | |||
| 1602 | fperrmsg (logfp, 0, 0, | |||
| 1603 | "ERROR: %s is a file, should be a directory!", | |||
| 1604 | repository); | |||
| 1605 | error (0, 0, "ERROR: %s is a file, should be a directory!", | |||
| 1606 | repository); | |||
| 1607 | err = 1; | |||
| 1608 | goto out; | |||
| 1609 | } | |||
| 1610 | if (noexec == 0 && CVS_MKDIRmkdir (repository, 0777) < 0) | |||
| 1611 | { | |||
| 1612 | ierrno = errno(*__errno()); | |||
| 1613 | fperrmsg (logfp, 0, ierrno, | |||
| 1614 | "ERROR: cannot mkdir %s -- not added", repository); | |||
| 1615 | error (0, ierrno, | |||
| 1616 | "ERROR: cannot mkdir %s -- not added", repository); | |||
| 1617 | err = 1; | |||
| 1618 | goto out; | |||
| 1619 | } | |||
| 1620 | } | |||
| 1621 | err = import_descend (message, vtag, targc, targv); | |||
| 1622 | out: | |||
| 1623 | if (rcs != NULL((void*)0)) | |||
| 1624 | free (rcs); | |||
| 1625 | if ((cp = strrchr (repository, '/')) != NULL((void*)0)) | |||
| 1626 | *cp = '\0'; | |||
| 1627 | else | |||
| 1628 | repository[0] = '\0'; | |||
| 1629 | if (restore_cwd (&cwd, NULL((void*)0))) | |||
| 1630 | error_exit (); | |||
| 1631 | free_cwd (&cwd); | |||
| 1632 | return (err); | |||
| 1633 | } |