1 /***************************************************************************
2  *
3  * $Header: /usr/local/cvsroot/utils/ytree/archive.c,v 1.16 2000/05/20 20:41:11 werner Exp $
4  *
5  * Allg. Funktionen zum Bearbeiten von Archiven
6  *
7  ***************************************************************************/
8 
9 
10 #include "ytree.h"
11 
12 
13 
14 static int GetArchiveDirEntry(DirEntry *tree, char *path, DirEntry **dir_entry);
15 
16 
InsertArchiveDirEntry(DirEntry * tree,char * path,struct stat * stat)17 static int InsertArchiveDirEntry(DirEntry *tree, char *path, struct stat *stat)
18 {
19   DirEntry *df_ptr, *de_ptr, *ds_ptr;
20   char father_path[PATH_LENGTH + 1];
21   char *p;
22   char name[PATH_LENGTH + 1];
23 
24 
25 #ifdef DEBUG
26   fprintf( stderr, "Insert Dir \"%s\"\n", path );
27 #endif
28 
29   /* Format: .../dir/ */
30   /*------------------*/
31 
32   (void) strcpy( father_path, path );
33 
34   if( ( p = strrchr( father_path, FILE_SEPARATOR_CHAR ) ) ) *p = '\0';
35   else
36   {
37     (void) sprintf( message, "path mismatch*missing '%c' in*%s",
38 	            FILE_SEPARATOR_CHAR,
39 	            path
40 	          );
41     ERROR_MSG( message );
42     return( -1 );
43   }
44 
45   p = strrchr( father_path, FILE_SEPARATOR_CHAR );
46 
47   if( p == NULL )
48   {
49     df_ptr = tree;
50     if( !strcmp( path, FILE_SEPARATOR_STRING ) )
51       (void) strcpy( name, path );
52     else
53       (void) strcpy( name, father_path );
54   }
55   else
56   {
57     (void) strcpy( name, ++p );
58     *p = '\0';
59     if( GetArchiveDirEntry( tree, father_path, &df_ptr ) )
60     {
61       (void) sprintf( message, "can't find subdir*%s", father_path );
62       ERROR_MSG( message );
63       return( -1 );
64     }
65   }
66 
67   if( ( de_ptr = (DirEntry *) malloc( sizeof( DirEntry ) + strlen( name ) ) ) == NULL )
68   {
69     ERROR_MSG( "Malloc failed*ABORT" );
70     exit( 1 );
71   }
72 
73   (void) memset( (char *) de_ptr, 0, sizeof( DirEntry ) );
74   (void) strcpy( de_ptr->name, name );
75   (void) memcpy( (char *) &de_ptr->stat_struct, (char *) stat, sizeof( struct stat ) );
76 
77 #ifdef DEBUG
78   fprintf( stderr, "new dir: \"%s\"\n", name );
79 #endif
80 
81 
82 
83   /* Directory einklinken */
84   /*----------------------*/
85 
86   if( p == NULL )
87   {
88     /* in tree (=df_ptr) einklinken */
89     /*------------------------------*/
90 
91     de_ptr->up_tree = df_ptr->up_tree;
92 
93     for( ds_ptr = df_ptr; ds_ptr; ds_ptr = ds_ptr->next )
94     {
95       if( strcmp( ds_ptr->name, de_ptr->name ) > 0 )
96       {
97         /* ds-Element ist groesser */
98         /*-------------------------*/
99 
100         de_ptr->next = ds_ptr;
101         de_ptr->prev = ds_ptr->prev;
102         if( ds_ptr->prev) ds_ptr->prev->next = de_ptr;
103         ds_ptr->prev = de_ptr;
104 	if( de_ptr->up_tree && de_ptr->up_tree->sub_tree == de_ptr->next )
105 	  de_ptr->up_tree->sub_tree = de_ptr;
106         break;
107       }
108 
109       if( ds_ptr->next == NULL )
110       {
111         /* Ende der Liste erreicht; ==> einfuegen */
112         /*----------------------------------------*/
113 
114         de_ptr->prev = ds_ptr;
115         de_ptr->next = ds_ptr->next;
116         ds_ptr->next = de_ptr;
117         break;
118       }
119     }
120   }
121   else if( df_ptr->sub_tree == NULL )
122   {
123     de_ptr->up_tree = df_ptr;
124     df_ptr->sub_tree = de_ptr;
125   }
126   else
127   {
128     de_ptr->up_tree = df_ptr;
129 
130     for( ds_ptr = df_ptr->sub_tree; ds_ptr; ds_ptr = ds_ptr->next )
131     {
132       if( strcmp( ds_ptr->name, de_ptr->name ) > 0 )
133       {
134         /* ds-Element ist groesser */
135         /*-------------------------*/
136 
137         de_ptr->next = ds_ptr;
138         de_ptr->prev = ds_ptr->prev;
139         if( ds_ptr->prev ) ds_ptr->prev->next = de_ptr;
140         ds_ptr->prev = de_ptr;
141 	if( de_ptr->up_tree->sub_tree == de_ptr->next )
142 	  de_ptr->up_tree->sub_tree = de_ptr;
143         break;
144       }
145 
146       if( ds_ptr->next == NULL )
147       {
148         /* Ende der Liste erreicht; ==> einfuegen */
149         /*----------------------------------------*/
150 
151         de_ptr->prev = ds_ptr;
152         de_ptr->next = ds_ptr->next;
153         ds_ptr->next = de_ptr;
154         break;
155       }
156     }
157   }
158   statistic.disk_total_directories++;
159   return( 0 );
160 }
161 
162 
163 
164 
165 
InsertArchiveFileEntry(DirEntry * tree,char * path,struct stat * stat)166 int InsertArchiveFileEntry(DirEntry *tree, char *path, struct stat *stat)
167 {
168   char dir[PATH_LENGTH + 1];
169   char file[PATH_LENGTH + 1];
170   DirEntry *de_ptr;
171   FileEntry *fs_ptr, *fe_ptr;
172   struct stat stat_struct;
173   int  n;
174 
175 
176   if( KeyPressed() )
177   {
178     Quit();  /* Abfrage, ob ytree verlassen werden soll */
179   }
180 
181 
182   Fnsplit( path, dir, file );
183 
184   if( GetArchiveDirEntry( tree, dir, &de_ptr ) )
185   {
186 #ifdef DEBUG
187     fprintf( stderr, "can't get directory for file*%s*trying recover", path );
188 #endif
189 
190     (void) memset( (char *) &stat_struct, 0, sizeof( struct stat ) );
191     stat_struct.st_mode = S_IFDIR;
192 
193     if( TryInsertArchiveDirEntry( tree, dir, &stat_struct ) )
194     {
195       ERROR_MSG( "inserting directory failed" );
196       return( -1 );
197     }
198     if( GetArchiveDirEntry( tree, dir, &de_ptr ) )
199     {
200       (void) sprintf( message, "again: can't get directory for file*%s*giving up", path );
201       ERROR_MSG( message );
202       return( -1 );
203     }
204   }
205 
206   if( S_ISLNK( stat->st_mode ) )
207     n = strlen( &path[ strlen( path ) + 1 ] ) + 1;
208   else
209     n = 0;
210 
211   if( ( fe_ptr = (FileEntry *) malloc( sizeof( FileEntry ) + strlen( file ) + n ) ) == NULL )
212   {
213     ERROR_MSG( "Malloc failed*ABORT" );
214     exit( 1 );
215   }
216 
217   (void) memset( fe_ptr, 0, sizeof( FileEntry ) );
218   (void) memcpy( (char *) &fe_ptr->stat_struct, (char *) stat, sizeof( struct stat ) );
219   (void) strcpy( fe_ptr->name, file );
220 
221   if( S_ISLNK( stat->st_mode ) )
222   {
223     (void) strcpy( &fe_ptr->name[ strlen( fe_ptr->name ) + 1 ],
224 		   &path[ strlen( path ) + 1 ]
225 		 );
226   }
227 
228   fe_ptr->dir_entry = de_ptr;
229   de_ptr->total_files++;
230   de_ptr->total_bytes += stat->st_size;
231   statistic.disk_total_files++;
232   statistic.disk_total_bytes += stat->st_size;
233 
234   /* Einklinken */
235   /*------------*/
236 
237   if( de_ptr->file == NULL )
238   {
239     de_ptr->file = fe_ptr;
240   }
241   else
242   {
243     for( fs_ptr = de_ptr->file; fs_ptr->next; fs_ptr = fs_ptr->next )
244       ;
245 
246     fe_ptr->prev = fs_ptr;
247     fs_ptr->next = fe_ptr;
248   }
249   return( 0 );
250 }
251 
252 
253 
254 
255 
GetArchiveDirEntry(DirEntry * tree,char * path,DirEntry ** dir_entry)256 static int GetArchiveDirEntry(DirEntry *tree, char *path, DirEntry **dir_entry)
257 {
258   int n;
259   DirEntry *de_ptr;
260   BOOL is_root = FALSE;
261 
262 #ifdef DEBUG
263   fprintf( stderr, "GetArchiveDirEntry: tree=%s, path=%s\n",
264   (tree) ? tree->name : "NULL", path );
265 #endif
266 
267   if( strchr( path, FILE_SEPARATOR_CHAR ) != NULL )
268   {
269     for( de_ptr = tree; de_ptr; de_ptr = de_ptr->next )
270     {
271       n = strlen( de_ptr->name );
272       if( !strcmp( de_ptr->name, FILE_SEPARATOR_STRING ) ) is_root = TRUE;
273 
274       if( n && !strncmp( de_ptr->name, path, n ) &&
275 	  (is_root || path[n] == '\0' || path[n] == FILE_SEPARATOR_CHAR ) )
276       {
277 	if( ( is_root && path[n] == '\0' ) ||
278 	    ( path[n] == FILE_SEPARATOR_CHAR && path[n+1] == '\0' ) )
279 	{
280 	  /* Pfad abgearbeitet; ==> fertig */
281 	  /*-------------------------------*/
282 
283 	  *dir_entry = de_ptr;
284 	  return( 0 );
285 	}
286 	else
287         {
288 	  return( GetArchiveDirEntry( de_ptr->sub_tree,
289 				  ( is_root ) ? &path[n] : &path[n+1],
290 				  dir_entry
291 				) );
292 	}
293       }
294     }
295   }
296   if( *path == '\0' )
297   {
298     *dir_entry = tree;
299     return( 0 );
300   }
301   return( -1 );
302 }
303 
304 
305 
306 
307 
TryInsertArchiveDirEntry(DirEntry * tree,char * dir,struct stat * stat)308 int TryInsertArchiveDirEntry(DirEntry *tree, char *dir, struct stat *stat)
309 {
310   DirEntry *de_ptr;
311   char dir_path[PATH_LENGTH + 1];
312   char *s, *t;
313 
314   (void) memset( dir_path, 0, sizeof( dir_path ) );
315 
316 #ifdef DEBUG
317   fprintf( stderr, "Try install start \n" );
318 #endif
319 
320   for( s=dir, t=dir_path; *s; s++, t++ )
321   {
322     if( (*t = *s) == FILE_SEPARATOR_CHAR )
323     {
324       if( GetArchiveDirEntry( tree, dir_path, &de_ptr ) == -1 )
325       {
326 	/* Evtl. fehlender teil; ==> einfuegen */
327 	/*-------------------------------------*/
328 
329 	if( InsertArchiveDirEntry( tree, dir_path, stat ) ) return( -1 );
330       }
331     }
332   }
333 
334 #ifdef DEBUG
335   fprintf( stderr, "Try install end\n" );
336 #endif
337 
338   return( 0 );
339 }
340 
341 
342 
343 
344 
345 
MinimizeArchiveTree(DirEntry * tree)346 int MinimizeArchiveTree(DirEntry *tree)
347 {
348   DirEntry  *de_ptr, *de1_ptr;
349   DirEntry  *next_ptr;
350   FileEntry *fe_ptr;
351 
352 
353   /* Falls tree einen Nachfolger hat und
354    * tree selbst leer ist, wird tree gestrichen
355    */
356 
357   if( tree->prev == NULL &&
358       tree->next != NULL &&
359       tree->file == NULL )
360   {
361     next_ptr = tree->next;
362     (void) memcpy( (char *) tree,
363 		   (char *) tree->next,
364 		   sizeof( DirEntry ) + strlen( tree->next->name )
365 		 );
366     tree->prev = NULL;
367     if( tree->next ) tree->next->prev = tree;
368     statistic.disk_total_directories--;
369     free( next_ptr );
370     for( fe_ptr=tree->file; fe_ptr; fe_ptr=fe_ptr->next)
371       fe_ptr->dir_entry = tree;
372     for( de_ptr=tree->sub_tree; de_ptr; de_ptr=de_ptr->next)
373       de_ptr->up_tree = tree;
374   }
375 
376 
377   /* Test, ob *de_ptr weder Vorgaenger noch Nachfolger noch Dateien hat */
378   /*--------------------------------------------------------------------*/
379 
380   for( de_ptr = tree->sub_tree; de_ptr; de_ptr = next_ptr )
381   {
382     if( de_ptr->prev == NULL && de_ptr->next == NULL && de_ptr->file == NULL )
383     {
384       /* Zusammenfassung moeglich */
385       /*--------------------------*/
386 
387       if( strcmp( tree->name, FILE_SEPARATOR_STRING ) )
388 	(void) strcat( tree->name, FILE_SEPARATOR_STRING );
389       (void) strcat( tree->name, de_ptr->name );
390       statistic.disk_total_directories--;
391       tree->sub_tree = de_ptr->sub_tree;
392       for( de1_ptr = de_ptr->sub_tree; de1_ptr; de1_ptr = de1_ptr->next )
393 	de1_ptr->up_tree = tree;
394       next_ptr = de_ptr->sub_tree;
395       free( de_ptr );
396 #ifdef DEBUG
397   fprintf( stderr, "new root-dir: \"%s\"\n", tree->name );
398 #endif
399       continue;
400     }
401     break;
402   }
403 
404   /* Letzter Optimierungsschritt:
405    * Falls tree weder Vorgaenger noch Nachfolger hat, aber
406    * einen Subtree der Files hat, wird zusammengefasst
407    */
408 
409   if( tree->prev == NULL &&
410       tree->next == NULL &&
411       tree->file == NULL &&
412       tree->sub_tree     &&
413       tree->sub_tree->prev == NULL &&
414       tree->sub_tree->next == NULL
415     )
416   {
417     de_ptr = tree->sub_tree;
418     (void) strcat( tree->name, FILE_SEPARATOR_STRING );
419     (void) strcat( tree->name, de_ptr->name );
420     tree->file = de_ptr->file;
421     for( fe_ptr=tree->file; fe_ptr; fe_ptr=fe_ptr->next )
422       fe_ptr->dir_entry = tree;
423     (void) memcpy( (char *) &tree->stat_struct,
424 		   (char *) &de_ptr->stat_struct,
425 		   sizeof( struct stat )
426 		  );
427     statistic.disk_total_directories--;
428     tree->sub_tree = de_ptr->sub_tree;
429     for( de1_ptr = de_ptr->sub_tree; de1_ptr; de1_ptr = de1_ptr->next )
430       de1_ptr->up_tree = tree;
431     free( de_ptr );
432   }
433   return( 0 );
434 }
435 
436 
437 
MakeExtractCommandLine(char * command_line,char * path,char * file,char * cmd)438 void MakeExtractCommandLine(char *command_line, char *path, char *file, char *cmd)
439 {
440   int  l;
441   char cat_path[PATH_LENGTH+1];
442   int  compress_method;
443 
444   compress_method = GetFileMethod( path );
445 
446   l = strlen( path );
447 
448   if( compress_method == ZOO_COMPRESS )
449   {
450     /* zoo xp FILE ?? */
451     /*----------------*/
452 
453     (void) sprintf( command_line, "%s '%s' '%s' %s",
454 		    ZOOEXPAND,
455 		    path,
456 		    file,
457 		    cmd
458 		  );
459   }
460   else if( compress_method == LHA_COMPRESS )
461   {
462     /* xlharc p FILE ?? */
463     /*------------------*/
464 
465     (void) sprintf( command_line, "%s '%s' '%s' %s",
466 		    LHAEXPAND,
467 		    path,
468 		    file,
469 		    cmd
470 		  );
471   }
472   else if( compress_method == ZIP_COMPRESS )
473   {
474     /* unzip -c FILE ?? */
475     /*------------------*/
476 
477     (void) sprintf( command_line, "%s '%s' '%s' %s",
478 		    ZIPEXPAND,
479 		    path,
480 		    file,
481 		    cmd
482 		  );
483   }
484   else if( compress_method == ARC_COMPRESS )
485   {
486     /* arc p FILE ?? */
487     /*---------------*/
488 
489     (void) sprintf( command_line, "%s '%s' '%s' %s",
490 		    ARCEXPAND,
491 		    path,
492 		    file,
493 		    cmd
494 		  );
495   }
496   else if( compress_method == RPM_COMPRESS )
497   {
498     /* TF=/tmp/ytree.$$; mkdir $TF; cd $TF; rpm2cpio RPM_FILE | cpio -id FILE;
499      * cat $TF/$2; cd /tmp; rm -rf $TF; exit 0
500      */
501 
502 
503     if(!strcmp(RPMEXPAND, "builtin")) {
504       (void) sprintf( command_line,
505     		    "(TF=/tmp/ytree.$$; mkdir $TF; rpm2cpio '%s' | (cd $TF; cpio --no-absolute-filenames -i -d '%s'); cat \"$TF/%s\"; cd /tmp; rm -rf $TF; exit 0) %s",
506 		    path,
507 		    (*file == FILE_SEPARATOR_CHAR) ? &file[1] : file,
508 		    file,
509 		    cmd
510 		  );
511     } else {
512       (void) sprintf( command_line, "%s '%s' '%s' %s",
513 		    RPMEXPAND,
514 		    path,
515 		    file,
516 		    cmd
517 		  );
518     }
519   }
520   else if( compress_method == RAR_COMPRESS )
521   {
522     /* rar p FILE ?? */
523     /*---------------*/
524 
525     (void) sprintf( command_line, "%s '%s' '%s' %s",
526 		    RAREXPAND,
527 		    path,
528 		    file,
529 		    cmd
530 		  );
531   }
532   else if( compress_method == FREEZE_COMPRESS )
533   {
534     /* melt < TAR_FILE | gtar xOf - FILE ?? */
535     /*--------------------------------------*/
536 
537     (void) sprintf( command_line, "%s < '%s' | %s '%s' %s",
538 		    MELT,
539 		    path,
540 		    TAREXPAND,
541 		    file,
542 		    cmd
543 		  );
544   }
545   else if( compress_method == MULTIPLE_FREEZE_COMPRESS )
546   {
547     /* CAT TAR_FILEs | melt | gtar xOf - FILE ?? */
548     /*-------------------------------------------*/
549 
550     (void) strncpy( cat_path, path, l - 2 );
551     (void) strcpy( &cat_path[l-2], "*" );
552 
553     (void) sprintf( command_line, "%s %s | %s | %s '%s' %s",
554 		    CAT,
555 		    cat_path,
556 		    MELT,
557 		    TAREXPAND,
558 		    file,
559 		    cmd
560 		  );
561   }
562   else if( compress_method == COMPRESS_COMPRESS )
563   {
564     /* uncompress < TAR_FILE | gtar xOf - FILE ?? */
565     /*--------------------------------------------*/
566 
567     (void) sprintf( command_line, "%s < %s | %s '%s' %s",
568 		    UNCOMPRESS,
569 		    path,
570 		    TAREXPAND,
571 		    file,
572 		    cmd
573 		  );
574   }
575   else if( compress_method == MULTIPLE_COMPRESS_COMPRESS )
576   {
577     /* CAT TAR_FILEs | uncompress | gtar xOf - FILE ?? */
578     /*-------------------------------------------------*/
579 
580     (void) strncpy( cat_path, path, l - 2 );
581     (void) strcpy( &cat_path[l-2], "*" );
582 
583     (void) sprintf( command_line, "%s %s | %s | %s '%s' %s",
584 		    CAT,
585 		    cat_path,
586 		    UNCOMPRESS,
587 		    TAREXPAND,
588 		    file,
589 		    cmd
590 		  );
591   }
592   else if( compress_method == GZIP_COMPRESS )
593   {
594     /* gunzip < TAR_FILE | gtar xOf - FILE ?? */
595     /*----------------------------------------*/
596 
597     (void) sprintf( command_line, "%s < '%s' | %s '%s' %s",
598 		    GNUUNZIP,
599 		    path,
600 		    TAREXPAND,
601 		    file,
602 		    cmd
603 		  );
604   }
605   else if( compress_method == MULTIPLE_GZIP_COMPRESS )
606   {
607     /* CAT TAR_FILEs | gunzip | gtar xOf - FILE ?? */
608     /*---------------------------------------------*/
609 
610     (void) strncpy( cat_path, path, l - 2 );
611     (void) strcpy( &cat_path[l-2], "*" );
612 
613     (void) sprintf( command_line, "%s %s | %s | %s '%s' %s",
614 		    CAT,
615 		    cat_path,
616 		    GNUUNZIP,
617 		    TAREXPAND,
618 		    file,
619 		    cmd
620 		  );
621   }
622   else if( compress_method == BZIP_COMPRESS )
623   {
624     /* bunzip2 < TAR_FILE | gtar xOf - FILE ?? */
625     /*----------------------------------------*/
626 
627     (void) sprintf( command_line, "%s < '%s' | %s '%s' %s",
628 		    BUNZIP,
629 		    path,
630 		    TAREXPAND,
631 		    file,
632 		    cmd
633 		  );
634   }
635   else
636   {
637     /* gtar xOf - FILE < TAR_FILE ?? */
638     /*-------------------------------*/
639 
640     (void) sprintf( command_line, "%s '%s' < '%s' %s",
641 		    TAREXPAND,
642 		    file,
643 		    path,
644 		    cmd
645 		  );
646   }
647 
648 #ifdef DEBUG
649   fprintf( stderr, "system( \"%s\" )\n", command_line );
650 #endif
651 
652 }
653 
654