1 /*
2 * Copyright (c) 2003 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
4 */
5
6 #include "config.h"
7
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <sys/param.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17
18 #include "argcargv.h"
19 #include "code.h"
20 #include "mkdirs.h"
21 #include "pathcmp.h"
22 #include "root.h"
23
24 int cksum = 1;
25 int verbose = 0;
26 int noupload = 0;
27 int case_sensitive = 1;
28 extern char *version;
29
30 struct node {
31 char path[ MAXPATHLEN ];
32 struct node *next;
33 };
34
35 struct node* create_node( char *path );
36 void free_node( struct node *node );
37
38 struct node *
create_node(char * path)39 create_node( char *path )
40 {
41 struct node *new_node;
42
43 if (( new_node = (struct node *) malloc( sizeof( struct node ))) == NULL ) {
44 perror( "malloc" );
45 return( NULL );
46 }
47 if ( strlen( path ) >= MAXPATHLEN ) {
48 fprintf( stderr, "%s: path too long\n", path );
49 return( NULL );
50 }
51 strcpy( new_node->path, path );
52
53 return( new_node );
54 }
55
56 void
free_node(struct node * node)57 free_node( struct node *node )
58 {
59 free( node );
60 }
61
62 struct tran {
63 struct node *t_next; /* Next tran in list */
64 FILE *t_fd; /* open file descriptor */
65 int t_num; /* Tran num from command line */
66 char *t_path; /* Path from command line */
67 int t_eof; /* Tran at end of file */
68 int t_linenum; /* Current line number */
69 int t_remove; /* Current line has '-' */
70 char t_prepath[ MAXPATHLEN ]; /* for order check */
71 char t_tran_root[ MAXPATHLEN ];
72 char t_file_root[ MAXPATHLEN ];
73 char t_tran_name[ MAXPATHLEN ];
74 char *t_line;
75 char t_tline[ 2 * MAXPATHLEN ];
76 char t_filepath[ MAXPATHLEN ];
77 char **t_argv;
78 int t_tac;
79 ACAV *t_acav;
80 };
81
82 int getnextline( struct tran *tran );
83
84 int
getnextline(struct tran * tran)85 getnextline( struct tran *tran )
86 {
87 int len;
88 char *d_path;
89
90 getline:
91 if ( fgets( tran->t_tline, MAXPATHLEN, tran->t_fd ) == NULL ) {
92 if ( feof( tran->t_fd )) {
93 tran->t_eof = 1;
94 return( 0 );
95 } else {
96 perror( tran->t_path );
97 return( -1 );
98 }
99 }
100 tran->t_linenum++;
101
102 if ( tran->t_line != NULL ) {
103 free( tran->t_line );
104 tran->t_line = NULL;
105 }
106
107 if ( ( tran->t_line = strdup( tran->t_tline ) ) == NULL ) {
108 perror( tran->t_tline );
109 return( -1 );
110 }
111
112 /* Check line length */
113 len = strlen( tran->t_tline );
114 if ( ( tran->t_tline[ len - 1 ] ) != '\n' ) {
115 fprintf( stderr, "%s: %d: %s: line too long\n", tran->t_tran_name,
116 tran->t_linenum, tran->t_tline );
117 return( -1 );
118 }
119 if ( ( tran->t_tac = acav_parse( tran->t_acav,
120 tran->t_tline, &(tran->t_argv) ) ) < 0 ) {
121 fprintf( stderr, "acav_parse\n" );
122 return( -1 );
123 }
124 /* Skip blank lines and comments */
125 if (( tran->t_tac == 0 ) || ( *tran->t_argv[ 0 ] == '#' )) {
126 goto getline;
127 }
128
129 if ( *tran->t_argv[ 0 ] == '-' ) {
130 tran->t_remove = 1;
131 tran->t_argv++;
132 } else {
133 tran->t_remove = 0;
134 }
135
136 /* Decode file path */
137 if (( d_path = decode( tran->t_argv[ 1 ] )) == NULL ) {
138 fprintf( stderr, "%s: line %d: path too long\n", tran->t_tran_name,
139 tran->t_linenum );
140 return( 1 );
141 }
142 if ( strlen( d_path ) >= MAXPATHLEN ) {
143 fprintf( stderr, "%s: line %d: %s: path too long\n",
144 tran->t_tran_name, tran->t_linenum, d_path );
145 return( 1 );
146 }
147 strcpy( tran->t_filepath, d_path );
148
149 /* Check transcript order */
150 if ( strlen( tran->t_prepath ) != 0 ) {
151
152 if ( pathcasecmp( tran->t_filepath, tran->t_prepath,
153 case_sensitive ) <= 0 ) {
154 fprintf( stderr, "%s: line %d: bad sort order\n",
155 tran->t_tran_name, tran->t_linenum );
156 return( 1 );
157 }
158 }
159 if ( strlen( tran->t_filepath ) >= MAXPATHLEN ) {
160 fprintf( stderr, "%s: line %d: %s: path too long\n",
161 tran->t_tran_name, tran->t_linenum, tran->t_filepath );
162 return( 1 );
163 }
164 strcpy( tran->t_prepath, tran->t_filepath );
165
166
167 return( 0 );
168 }
169
170 static int
copy_file(const char * src_file,const char * dest_file)171 copy_file( const char *src_file, const char *dest_file )
172 {
173 int src_fd, dest_fd = -1;
174 int rr, rc = -1;
175 char buf[ 4096 ];
176 struct stat st;
177
178 if (( src_fd = open( src_file, O_RDONLY )) < 0 ) {
179 fprintf( stderr, "open %s failed: %s\n", src_file, strerror( errno ));
180 return( rc );
181 }
182 if ( fstat( src_fd, &st ) < 0 ) {
183 fprintf( stderr, "stat of %s failed: %s\n",
184 src_file, strerror( errno ));
185 goto cleanup;
186 }
187
188 if (( dest_fd = open( dest_file, O_WRONLY | O_CREAT | O_EXCL,
189 st.st_mode & 07777 )) < 0 ) {
190 if ( errno == ENOENT ) {
191 rc = errno;
192 } else {
193 fprintf( stderr, "open %s failed: %s\n",
194 dest_file, strerror( errno ));
195 }
196 goto cleanup;
197 }
198 while (( rr = read( src_fd, buf, sizeof( buf ))) > 0 ) {
199 if ( write( dest_fd, buf, rr ) != rr ) {
200 fprintf( stderr, "write to %s failed: %s\n",
201 dest_file, strerror( errno ));
202 goto cleanup;
203 }
204 }
205 if ( rr < 0 ){
206 fprintf( stderr, "read from %s failed: %s\n",
207 src_file, strerror( errno ));
208 goto cleanup;
209 }
210 if ( fchown( dest_fd, st.st_uid, st.st_gid ) != 0 ) {
211 fprintf( stderr, "chown %d:%d %s failed: %s\n",
212 st.st_uid, st.st_gid, dest_file, strerror( errno ));
213 goto cleanup;
214 }
215
216 rc = 0;
217
218 cleanup:
219 if ( src_fd >= 0 ) {
220 if ( close( src_fd ) != 0 ) {
221 fprintf( stderr, "close %s failed: %s\n",
222 src_file, strerror( errno ));
223 rc = -1;
224 }
225 }
226 if ( dest_fd >= 0 ) {
227 if ( close( dest_fd ) != 0 ) {
228 fprintf( stderr, "close %s failed: %s\n",
229 dest_file, strerror( errno ));
230 rc = -1;
231 }
232 }
233
234 return( rc );
235 }
236
237 /*
238 * exit codes:
239 * 0 okay
240 * 2 System error
241 */
242
243 int
main(int argc,char ** argv)244 main( int argc, char **argv )
245 {
246 int c, i, j, cmpval, err = 0, tcount = 0, candidate = 0;
247 int force = 0, ofd, fileloc = 0, match = 0;
248 int merge_trans_only = 0;
249 int copy = 0, rc;
250 char *file = NULL;
251 char npath[ 2 * MAXPATHLEN ];
252 char opath[ 2 * MAXPATHLEN ];
253 char *radmind_path = _RADMIND_PATH;
254 char cwd[ MAXPATHLEN ];
255 char file_root[ MAXPATHLEN ];
256 char tran_root[ MAXPATHLEN ];
257 char tran_name[ MAXPATHLEN ];
258 char temp[ MAXPATHLEN ];
259 struct tran **trans = NULL;
260 struct node *new_node = NULL;
261 struct node *node = NULL;
262 struct node *dirlist = NULL;
263 FILE *ofs;
264 mode_t mask;
265
266 while ( ( c = getopt( argc, argv, "CD:fInTu:Vv" ) ) != EOF ) {
267 switch( c ) {
268 case 'C': /* copy files instead of using hardlinks */
269 copy = 1;
270 break;
271 case 'D':
272 radmind_path = optarg;
273 break;
274 case 'f':
275 force = 1;
276 break;
277 case 'I':
278 case_sensitive = 0;
279 break;
280 case 'n':
281 noupload = 1;
282 break;
283 case 'u':
284 errno = 0;
285 mask = (mode_t)strtol( optarg, (char **)NULL, 0 );
286 if ( errno != 0 ) {
287 err++;
288 break;
289 }
290 umask( mask );
291 break;
292 case 'V':
293 printf( "%s\n", version );
294 exit( 0 );
295 case 'v':
296 verbose = 1;
297 break;
298 case 'T':
299 merge_trans_only = 1;
300 break;
301 default:
302 err++;
303 break;
304 }
305 }
306
307 tcount = argc - ( optind + 1 ); /* "+ 1" accounts for dest tran */
308
309 if ( merge_trans_only && force ) {
310 err++;
311 }
312 if ( merge_trans_only && copy ) {
313 err++;
314 }
315 if ( noupload && ( tcount > 2 ) ) {
316 err++;
317 }
318 /* make sure there's a second transcript */
319 if ( force && ( argv[ optind + 1 ] == NULL )) {
320 err++;
321 }
322 if ( force && ( tcount > 1 ) ) {
323 err++;
324 }
325 if ( !force && ( tcount < 2 )) {
326 err++;
327 }
328
329 if ( err ) {
330 fprintf( stderr, "Usage: %s [-vCIVT] [ -D path ] [ -u umask ] ",
331 argv[ 0 ] );
332 fprintf( stderr, "transcript... dest\n" );
333 fprintf( stderr, " %s -f [-vCIV] [ -D path ] [ -u umask ] ",
334 argv[ 0 ] );
335 fprintf( stderr, "transcript1 transcript2\n" );
336 fprintf( stderr, " %s -n [-vCIVT] [ -D path ] [ -u umask ] ",
337 argv[ 0 ] );
338 fprintf( stderr, "transcript1 transcript2 dest\n" );
339 exit( 2 );
340 }
341
342 if ( force ) {
343 /* Check for write access */
344 if ( access( argv[ argc - 1 ], W_OK ) != 0 ) {
345 perror( argv[ argc - 1 ] );
346 exit( 2 );
347 }
348 tcount++; /* add dest to tran merge list */
349 }
350
351 /* Create array of transcripts */
352 if (( trans = (struct tran**)malloc(
353 sizeof( struct tran* ) * ( tcount ))) == NULL ) {
354 perror( "malloc" );
355 exit( 2 );
356 }
357 if ( getcwd( cwd, MAXPATHLEN ) == NULL ) {
358 perror( "getcwd" );
359 exit( 2 );
360 }
361
362 /* loop over array of trans */
363 for ( i = 0; i < tcount; i++ ) {
364
365 if ( ( trans[ i ] = (struct tran*)malloc( sizeof( struct tran ) ) )
366 == NULL ) {
367 perror( "malloc" );
368 return( 1 );
369 }
370 memset( trans[ i ], 0, sizeof( struct tran ));
371 trans[ i ]->t_num = i;
372 trans[ i ]->t_path = argv[ i + optind ];
373
374 if ( get_root( radmind_path, trans[ i ]->t_path, trans[ i ]->t_file_root,
375 trans[ i ]->t_tran_root, trans[ i ]->t_tran_name ) != 0 ) {
376 exit( 2 );
377 }
378
379 /* open tran */
380 if (( trans[ i ]->t_fd = fopen( trans[ i ]->t_path, "r" )) == NULL ) {
381 perror( trans[ i ]->t_path );
382 return( 1 );
383 }
384
385 if ( ( trans[ i ]->t_acav = acav_alloc() ) == NULL ) {
386 fprintf( stderr, "acav_malloc\n" );
387 return( 1 );
388 }
389 trans[ i ]->t_line = NULL;
390 if ( getnextline( trans[ i ] ) < 0 ) {
391 exit( 2 );
392 }
393 }
394
395 if ( force ) {
396 if ( strlen( trans[ 1 ]->t_file_root ) >= MAXPATHLEN ) {
397 fprintf( stderr, "%s: path too long\n", trans[ 1 ]->t_file_root );
398 exit( 2 );
399 }
400 strcpy( file_root, trans[ 1 ]->t_file_root );
401 if ( strlen( trans[ 1 ]->t_tran_root ) >= MAXPATHLEN ) {
402 fprintf( stderr, "%s: path too long\n", trans[ 1 ]->t_tran_root );
403 exit( 2 );
404 }
405 strcpy( tran_root, trans[ 1 ]->t_tran_root );
406 if ( strlen( trans[ 1 ]->t_tran_name ) >= MAXPATHLEN ) {
407 fprintf( stderr, "%s: path too long\n", trans[ 1 ]->t_tran_name );
408 exit( 2 );
409 }
410 strcpy( tran_name, trans[ 1 ]->t_tran_name );
411 } else {
412 /* Create tran if missing */
413 if (( ofd = open( argv[ argc - 1 ], O_WRONLY | O_CREAT, 0666 ) ) < 0 ) {
414 perror( argv[ argc - 1 ] );
415 exit( 2 );
416 }
417 if ( close( ofd ) != 0 ) {
418 perror( argv[ argc - 1 ] );
419 exit( 2 );
420 }
421
422 /* Get paths */
423 if ( *argv[ argc - 1 ] == '/' ) {
424 if ( strlen( argv[ argc - 1 ] ) >= MAXPATHLEN ) {
425 fprintf( stderr, "%s: path too long\n", argv[ argc - 1 ] );
426 exit( 2 );
427 }
428 strcpy( cwd, argv[ argc - 1 ] );
429 } else {
430 if ( snprintf( temp, MAXPATHLEN, "%s/%s", cwd, argv[ argc - 1 ] )
431 >= MAXPATHLEN ) {
432 fprintf( stderr, "%s/%s: path too long\n", cwd,
433 argv[ argc - 1 ] );
434 exit( 2 );
435 }
436 strcpy( cwd, temp );
437 }
438 if ( get_root( radmind_path, cwd, file_root, tran_root, tran_name ) != 0 ) {
439 exit( 2 );
440 }
441
442 /* Create file/tname dir */
443 if ( snprintf( npath, MAXPATHLEN, "%s/%s.%d", file_root, tran_name,
444 (int)getpid()) >= MAXPATHLEN ) {
445 fprintf( stderr, "%s/%s.%d: path too long\n", file_root, tran_name,
446 (int)getpid());
447 exit( 2 );
448 }
449 /* don't bother creating file/tname if only merging trans */
450 if ( !merge_trans_only ) {
451 if ( mkdir( npath, (mode_t)0777 ) != 0 ) {
452 perror( npath );
453 exit( 2 );
454 }
455 }
456 }
457
458 /* Create temp transcript/tname file */
459 if ( snprintf( opath, MAXPATHLEN, "%s/%s.%d", tran_root, tran_name,
460 (int)getpid()) >= MAXPATHLEN ) {
461 fprintf( stderr, "%s/%s.%d: path too long\n", tran_root, tran_name,
462 (int)getpid());
463 exit( 2 );
464 }
465 if (( ofd = open( opath, O_WRONLY | O_CREAT | O_EXCL,
466 0666 ) ) < 0 ) {
467 perror( opath );
468 exit( 2 );
469 }
470 if ( ( ofs = fdopen( ofd, "w" ) ) == NULL ) {
471 perror( opath );
472 exit( 2 );
473 }
474
475 /* merge */
476 for ( i = 0; i < tcount; i++ ) {
477 while ( !(trans[ i ]->t_eof)) {
478 candidate = i;
479 fileloc = i;
480 match = 0;
481
482 if ( force && ( candidate == ( tcount - 1 ))) {
483 match = 1;
484 goto outputline;
485 }
486
487 /* Compare candidate to other transcripts */
488 for ( j = i + 1; j < tcount; j++ ) {
489 if ( trans[ j ]->t_eof ) {
490 continue;
491 }
492 cmpval = pathcasecmp( trans[ candidate ]->t_filepath,
493 trans[ j ]->t_filepath, case_sensitive );
494 if ( cmpval == 0 ) {
495 /* File match */
496 match = 1;
497
498 if (( noupload ) &&
499 ( *trans[ candidate ]->t_argv[ 0 ] == 'f'
500 || *trans[ candidate ]->t_argv[ 0 ] == 'a' )) {
501 /* Use lower precedence path */
502 trans[ candidate ]->t_path =
503 trans[ j ]->t_path;
504
505 /* Select which file should be linked */
506 if ( ( strcmp( trans[ candidate ]->t_argv[ 6 ],
507 trans[ j ]->t_argv[ 6 ] ) == 0 ) &&
508 ( strcmp( trans[ candidate ]->t_argv[ 7 ],
509 trans[ j ]->t_argv[ 7 ] ) == 0 ) ) {
510 fileloc = j;
511 } else {
512 /* don't print file only in highest tran */
513 goto skipline;
514 }
515 }
516 if ( ( force ) && ( *trans[ j ]->t_argv[ 0 ] == 'f'
517 || *trans[ j ]->t_argv[ 0 ] == 'a' )) {
518 /* Remove file from lower precedence transcript */
519 if ( snprintf( opath, MAXPATHLEN, "%s/%s/%s",
520 trans[ j ]->t_file_root,
521 trans[ j ]->t_tran_name,
522 trans[ j ]->t_filepath ) >= MAXPATHLEN ) {
523 fprintf( stderr,
524 "%s/%s/%s: path too long\n",
525 trans[ j ]->t_file_root,
526 trans[ j ]->t_tran_name,
527 trans[ j ]->t_filepath );
528 exit( 2 );
529 }
530 if ( unlink( opath ) != 0 ) {
531 perror( opath );
532 exit( 2 );
533 }
534 if ( verbose ) printf( "%s: %s: unlinked\n",
535 trans[ j ]->t_tran_name, trans[ j ]->t_filepath);
536 }
537 /* Advance lower precedence transcript */
538 if ( getnextline( trans[ j ] ) < 0 ) {
539 exit( 2 );
540 }
541 } else if ( cmpval > 0 ) {
542 candidate = j;
543 fileloc = j;
544 }
545 }
546 if ( force && ( candidate == 1 ) ) {
547 goto outputline;
548 }
549 /* skip items to be removed or files not uploaded */
550 if (( trans[ candidate ]->t_remove ) ||
551 (( noupload ) && ( candidate == 0 ) && ( fileloc == 0 ))) {
552 if ( match && force &&
553 ( *trans[ candidate ]->t_argv[ 0 ] == 'd' )) {
554 new_node = create_node( trans[ candidate ]->t_argv[ 1 ] );
555 new_node->next = dirlist;
556 dirlist = new_node;
557 }
558 goto skipline;
559 }
560 /* output non-files, or if we're only merging transcripts
561 * and there is no file linking necessary
562 */
563 if (( *trans[ candidate ]->t_argv[ 0 ] != 'f'
564 && *trans[ candidate ]->t_argv[ 0 ] != 'a')
565 || merge_trans_only ) {
566 goto outputline;
567 }
568
569 /*
570 * Assume that directory structure is present so the entire path
571 * is not recreated for every file. Only if link fails is
572 * mkdirs() called.
573 */
574 if ( snprintf( opath, MAXPATHLEN, "%s/%s/%s",
575 trans[ candidate ]->t_file_root,
576 trans[ fileloc ]->t_tran_name,
577 trans[ candidate ]->t_filepath ) >= MAXPATHLEN ) {
578 fprintf( stderr, "%s/%s/%s: path too long\n",
579 trans[ candidate ]->t_file_root,
580 trans[ fileloc ]->t_tran_name,
581 trans[ candidate ]->t_filepath );
582 exit( 2 );
583 }
584
585 if ( !force ) {
586 if ( snprintf( npath, MAXPATHLEN, "%s/%s.%d/%s",
587 file_root, tran_name, (int)getpid(),
588 trans[ candidate ]->t_filepath ) >= MAXPATHLEN ) {
589 fprintf( stderr, "%s/%s.%d/%s: path too long\n",
590 file_root, tran_name, (int)getpid(),
591 trans[ candidate ]->t_filepath );
592 exit( 2 );
593 }
594 } else {
595 if ( snprintf( npath, MAXPATHLEN, "%s/%s/%s", file_root,
596 tran_name, trans[ candidate ]->t_filepath )
597 >= MAXPATHLEN ) {
598 fprintf( stderr, "%s/%s/%s: path too long\n",
599 file_root, tran_name, trans[ candidate ]->t_filepath );
600 exit( 2 );
601 }
602 }
603
604 /*
605 * copy or link file into new loadset. it's possible the file's
606 * directory hierarchy won't exist yet. in that case, we catch
607 * ENOENT, call mkdirs to create the parents dirs for the file,
608 * and try again. the second error is fatal.
609 */
610 if ( copy ) {
611 rc = copy_file( opath, npath );
612 } else if (( rc = link( opath, npath )) != 0 ) {
613 rc = errno;
614 }
615
616 if ( rc == ENOENT ) {
617
618 /* If that fails, verify directory structure */
619 if ( ( file = strrchr( trans[ candidate ]->t_argv[ 1 ], '/' ) )
620 != NULL ) {
621 if ( !force ) {
622 if ( snprintf( npath, MAXPATHLEN,
623 "%s/%s.%d/%s",
624 file_root, tran_name, (int)getpid(),
625 trans[ candidate ]->t_filepath )
626 >= MAXPATHLEN ) {
627 fprintf( stderr,
628 "%s/%s.%d/%s: path too long\n",
629 file_root, tran_name, (int)getpid(),
630 trans[ candidate ]->t_filepath );
631 exit( 2 );
632 }
633 } else {
634 if ( snprintf( npath, MAXPATHLEN,
635 "%s/%s/%s", file_root, tran_name,
636 trans[ candidate ]->t_filepath )
637 >= MAXPATHLEN ) {
638 fprintf( stderr,
639 "%s/%s/%s: path too long\n", file_root,
640 tran_name, trans[ candidate ]->t_filepath );
641 exit( 2 );
642 }
643 }
644 if ( mkdirs( npath ) != 0 ) {
645 fprintf( stderr, "%s: mkdirs failed\n", npath );
646 exit( 2 );
647 }
648 }
649
650 /* Try copy / link again */
651 if ( copy ) {
652 if (( rc = copy_file( opath, npath )) != 0 ) {
653 fprintf( stderr, "copy %s to %s failed\n",
654 opath, npath );
655 exit( 2 );
656 }
657 } else if ( link( opath, npath ) != 0 ){
658 fprintf( stderr, "link %s -> %s: %s\n",
659 opath, npath, strerror( errno ));
660 exit( 2 );
661 }
662 } else if ( rc ) {
663 if ( copy ) {
664 fprintf( stderr, "copy %s to %s failed\n", opath, npath );
665 } else {
666 fprintf( stderr, "link %s to %s failed: %s\n",
667 opath, npath, strerror( rc ));
668 }
669 exit( 2 );
670 }
671
672 if ( verbose ) printf( "%s: %s: merged into: %s\n",
673 trans[ candidate ]->t_tran_name, trans[ candidate ]->t_filepath,
674 tran_name );
675
676 outputline:
677 /* Output line */
678 if ( fputs( trans[ candidate ]->t_line, ofs ) == EOF ) {
679 perror( trans[ candidate ]->t_line );
680 exit( 2 );
681 }
682 skipline:
683 /* Don't duplicate remove line if it's not a match, or
684 * we got -f and we're just outputing the last
685 * transcript.
686 */
687 if (( trans[ candidate ]->t_remove )
688 && !match
689 && (!( force && ( candidate == 1 )))) {
690 /* Recreate unmatched "-" line */
691 if ( fputs( trans[ candidate ]->t_line, ofs ) == EOF ) {
692 perror( trans[ candidate ]->t_line );
693 exit( 2 );
694
695 }
696 }
697 if ( getnextline( trans[ candidate ] ) != 0 ) {
698 exit( 2 );
699 }
700 }
701 }
702
703 if ( force ) {
704 while ( dirlist != NULL ) {
705 node = dirlist;
706 dirlist = node->next;
707 if ( snprintf( opath, MAXPATHLEN, "%s/%s/%s", file_root,
708 tran_name, node->path ) >= MAXPATHLEN ) {
709 fprintf( stderr, "%s/%s/%s: path too long\n",
710 file_root, tran_name, node->path );
711 exit( 2 );
712 }
713 if ( rmdir( opath ) != 0 ) {
714 if (( errno == EEXIST ) || ( errno == ENOTEMPTY )) {
715 fprintf( stderr, "%s: %s: Not empty, continuing...\n",
716 tran_name, node->path );
717 } else if ( errno != ENOENT ) {
718 perror( opath );
719 exit( 2 );
720 }
721 } else {
722 if ( verbose ) printf( "%s: %s: unlinked\n", tran_name,
723 node->path );
724 }
725 free_node( node );
726 }
727 }
728
729 /* Rename temp transcript and file structure */
730 if ( !force ) {
731 if ( snprintf( opath, MAXPATHLEN, "%s/%s.%d", file_root,
732 tran_name, (int)getpid()) >= MAXPATHLEN ) {
733 fprintf( stderr, "%s/%s.%d: path too long\n",
734 file_root, tran_name, (int)getpid());
735 exit( 2 );
736 }
737 if ( snprintf( npath, MAXPATHLEN, "%s/%s", file_root, tran_name )
738 >= MAXPATHLEN ) {
739 fprintf( stderr, "%s/%s: path too long\n", file_root, tran_name );
740 exit( 2 );
741 }
742 /* don't try and move file/tname if doing client only merge,
743 * it was never created.
744 */
745 if ( !merge_trans_only ) {
746 if ( rename( opath, npath ) != 0 ) {
747 perror( npath );
748 exit( 2 );
749 }
750 }
751 }
752 if ( snprintf( opath, MAXPATHLEN, "%s/%s.%d", tran_root, tran_name,
753 (int)getpid()) >= MAXPATHLEN ) {
754 fprintf( stderr, "%s/%s.%d: path too long\n", tran_root, tran_name,
755 (int)getpid());
756 exit( 2 );
757 }
758 if ( snprintf( npath, MAXPATHLEN, "%s/%s", tran_root, tran_name )
759 >= MAXPATHLEN ) {
760 fprintf( stderr, "%s/%s: path too long\n", tran_root, tran_name );
761 exit( 2 );
762 }
763
764 if ( rename( opath, npath ) != 0 ) {
765 perror( npath );
766 exit( 2 );
767 }
768
769 exit( 0 );
770 }
771