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 | } |