f2a951467e56b69da1c17242dc2210fe213c5752
[oweals/cde.git] / cde / lib / tt / bin / tttar / tttar_api.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 //%%  (c) Copyright 1993, 1994 Hewlett-Packard Company                  
24 //%%  (c) Copyright 1993, 1994 International Business Machines Corp.    
25 //%%  (c) Copyright 1993, 1994 Sun Microsystems, Inc.                   
26 //%%  (c) Copyright 1993, 1994 Novell, Inc.                             
27 //%%  $XConsortium: tttar_api.C /main/4 1995/10/20 16:59:54 rswiston $                                                  
28 /*
29  * tttar_api.cc - ToolTalk object archiving interface functions.
30  *
31  * Copyright (c) 1990 by Sun Microsystems, Inc.
32  *
33  */
34
35 #include <errno.h>
36 #if defined(__osf__) || defined(linux) || defined(CSRG_BASED) || defined(sun)
37 #include <unistd.h>
38 #else
39 #ifndef USL
40 #include <osfcn.h>
41 #endif
42 #endif
43 #include <sys/param.h>
44 #include "api/c/api_api.h"
45 #include "api/c/tt_c.h"
46 #include "util/tt_path.h"
47 #include "util/tt_gettext.h"
48 #include "tttar_utils.h"
49 #include "tttar_file_utils.h"
50 #include "tttar_spec.h"
51 #include "tttar_api.h"
52
53 /*
54  * Type definitions
55  */
56
57
58 /*
59  * Constants
60  */
61
62 // Number of buckets in a hash table of interesting specs in an archive.
63 #define SPEC_MAP_SIZE   1000
64
65 /*
66  * Private functions
67  */
68 static bool_t           path_lstt_archive(
69                                 _Tt_string      path,
70                                 int             verbosity,
71                                 XDR            *xdrs );
72 bool_t                  dearchive_this_path(
73                                 char *path, void *ppaths_to_extract );
74 static Tt_filter_action         gather_specs( const char *spec_id, void *,
75                                 void *specs);
76
77 /*
78  * pathlist_lstt_archive() - Archive the LS/TT objects in the given paths.
79  */
80 bool_t
81 pathlist_lstt_archive(
82         _Tt_string_list_ptr     paths,
83         bool_t                  recurse,
84         bool_t                  follow_symlinks,
85         int                     verbosity,
86         XDR                    *xdrs )
87 {
88         _Tt_string_list_ptr     realpaths2tar;
89         Object_kind             obj_kind;
90         _Tt_string_list_ptr     paths_copy(new _Tt_string_list);
91         _Tt_string_list_cursor  path_cursor( paths );
92         while (path_cursor.next()) {
93                 paths_copy->append( *path_cursor );
94         }
95         
96         bool_t need_preliminary_pass = follow_symlinks && recurse;
97         realpaths2tar = realtrees( paths_copy, need_preliminary_pass );
98         
99         obj_kind = VERSION_NUM;
100         int version = CURRENT_ARCHIVE_VERSION;
101         if (    (! xdr_enum( xdrs, (enum_t *)&obj_kind ))
102                 || (! xdr_int( xdrs, &version )))
103         {
104                 fprintf( stderr, "%s: ! xdr_enum() || ! xdr_int()\n",
105                          (char *)our_process_name );
106                 return FALSE;
107         }
108         while (! paths_copy->is_empty()) {
109                 _Tt_string_list_ptr     children;
110                 _Tt_string              path( paths_copy->top() );
111                 
112                 paths_copy->pop();
113                 if (! path_lstt_archive( path, verbosity, xdrs ))
114                 {
115                         return FALSE;
116                 }
117                 if (recurse) {
118                         children = _tt_dir_entries( path, follow_symlinks );
119                         children->append_destructive( paths_copy );
120                         paths_copy = children;
121                 }
122         }
123         obj_kind = ARCHIVE_END;
124         if (! xdr_enum( xdrs, (enum_t *)&obj_kind )) {
125                 fprintf( stderr, "%s: ! xdr_enum()\n",
126                          (char *)our_process_name );
127                 return FALSE;
128         }
129         return TRUE;
130         
131 } /* pathlist_lstt_archive() */
132
133 /*
134 * pathlist_lstt_dearchive() - Extract the LS/TT objects of the given paths.
135  *      If no paths are given, extract everything in the archive.
136  */
137 bool_t
138 pathlist_lstt_dearchive(
139         _Tt_string_list_ptr     paths_to_extract,
140         Lstar_string_map_list_ptr renamings,
141         _Tt_string              where_to_dearchive,
142         bool_t                  preserve__props,
143         int                     verbosity,
144         XDR                    *xdrs )
145 {
146         _Tt_string                      last_path;
147         char                           *this_path       = NULL;
148         int                             num_specs       = 0;
149         int                             num_links       = 0;
150         bool_t                          last_path_valid = FALSE;
151         Object_kind                     obj_kind        = NO_KIND;
152         Lstar_string_map_table_ptr      spec_map;
153         int                             mem_mark        = tt_mark();
154
155         spec_map = new Lstar_string_map_table(Lstar_string_map_old_string,
156                                               SPEC_MAP_SIZE );
157         do {
158                 bool_t  just_dearchived_spec = FALSE;
159                 bool_t  just_dearchived_link = FALSE;
160
161                 if (! xdr_enum( xdrs, (enum_t *)&obj_kind )) {
162                         fprintf( stderr,
163                                  catgets(_ttcatd, 7, 4,
164                                          "%s: Could not read object kind "
165                                          "from archive stream.\n"),
166                                  (char *)our_process_name );
167                         return FALSE;
168                 }
169                 switch (obj_kind) {
170                     case VERSION_NUM:
171                         int version;
172                         if (! xdr_int( xdrs, &version)) {
173                                 fprintf( stderr,
174                                          catgets(_ttcatd, 7, 5,
175                                                  "%s: Could not read archive ver"
176                                                  "sion from archive stream.\n"),
177                                          (char *)our_process_name );
178                                 return FALSE;
179                         }
180                         if (version != CURRENT_ARCHIVE_VERSION) {
181                                 fprintf( stderr,
182                                          catgets(_ttcatd, 7, 6,
183                                                  "%s: Found archive version %d, "
184                                                  "but expected version %d.\n"),
185                                          (char *)our_process_name, version,
186                                          CURRENT_ARCHIVE_VERSION );
187                                 return FALSE;
188                         }
189                         break;
190                     case SPEC:
191                         char           *old_spec_id;
192                         char           *new_spec_id;
193                         Tt_status       err;
194
195                         old_spec_id     = NULL;
196                         new_spec_id     = NULL;
197                         err             = TT_OK;
198
199                         if (! spec_dearchive( &old_spec_id, &new_spec_id,
200                                               &this_path, renamings,
201                                               (char *)where_to_dearchive,
202                                               preserve__props,
203                                               dearchive_this_path,
204                                               (void *)&paths_to_extract,
205                                               verbosity,
206                                               xdrs, &err ))
207                         {
208                                 my_tt_release( mem_mark );
209                                 return FALSE;
210                         }
211                         if (new_spec_id != NULL) {
212                                 Lstar_string_map_ptr m = new Lstar_string_map;
213
214                                 m->old_string_set( old_spec_id );
215                                 m->new_string_set( new_spec_id );
216                                 m->extra_set( this_path );
217                                 spec_map->insert( m );
218                                 num_specs++;
219                                 just_dearchived_spec = TRUE;
220                         }
221                         break;
222                     case ARCHIVE_END:
223                         break;
224                     case NO_KIND:
225                     default:
226                         fprintf( stderr,
227                                  catgets(_ttcatd, 7, 7,
228                                          "%s: found object of unknown kind "
229                                          "%d in archive.\n"),
230                                  (char *)our_process_name, (int)obj_kind );
231                         return FALSE;
232                 }
233                 if (verbosity && (    (last_path != (const char *)this_path)
234                                  || (obj_kind == ARCHIVE_END)))
235                 {
236                         if (last_path_valid) {
237                                 if (just_dearchived_spec) {
238                                         num_specs--;
239                                 } else if (just_dearchived_link) {
240                                         num_links--;
241                                 }
242                                 if (verbosity > 1) {
243                                         fprintf( stderr, "\n" );
244                                 }
245                                 if ( (num_specs > 0) || (num_links > 0)) {
246                                         fprintf( stderr, "x %s %d %s\n",
247                                                  (char *)last_path, num_specs,
248                                                  (   num_specs == 1
249                                                    ? "spec" : "specs" ));
250                                 }
251                                 num_specs = 0;
252                                 num_links = 0;
253                                 if (just_dearchived_spec) {
254                                         num_specs = 1;
255                                 } else if (just_dearchived_link)  {
256                                         num_links = 1;
257                                 }
258                         }
259                         last_path = this_path;
260                         if (! last_path_valid) {
261                                 last_path_valid = TRUE;
262                         }
263                 }
264         } while (obj_kind != ARCHIVE_END);
265         my_tt_release( mem_mark );
266         return TRUE;
267
268 } /* pathlist_lstt_dearchive() */
269
270 /*
271  * pathlist_lstt_archive_list() - List the LS/TT objects of the given paths.
272  *      If no paths are given, list everything in the archive.
273  */
274 bool_t
275 pathlist_lstt_archive_list(
276         _Tt_string_list_ptr     paths_to_list,
277         int                     verbosity,
278         XDR                    *xdrs )
279 {
280         _Tt_string      last_path;
281         _Tt_string      this_path;
282         int             num_specs       = 0;
283         int             num_links       = 0;
284         bool_t          last_path_valid = FALSE;
285         Object_kind     obj_kind        = NO_KIND;
286         Lstar_string_map_table_ptr      spec_map;
287         int             mem_mark        = tt_mark();
288
289         spec_map = new Lstar_string_map_table(Lstar_string_map_old_string,
290                                               SPEC_MAP_SIZE );
291         do {
292                 Lstar_spec      spec;
293
294                 if (! xdr_enum( xdrs, (enum_t *)&obj_kind )) {
295                         fprintf( stderr,
296                                  catgets(_ttcatd, 7, 8,
297                                          "%s: Could not read object kind "
298                                          "from archive stream.\n"),
299                                  (char *)our_process_name );
300                         return FALSE;
301                 }
302                 switch (obj_kind) {
303                     case VERSION_NUM:
304                         int version;
305                         if (! xdr_int( xdrs, &version)) {
306                                 fprintf( stderr,
307                                          catgets(_ttcatd, 7, 9,
308                                                  "%s: Could not read archive ver"
309                                                  "sion from archive stream.\n"),
310                                          (char *)our_process_name );
311                                 return FALSE;
312                         }
313                         if (version != CURRENT_ARCHIVE_VERSION) {
314                                 fprintf( stderr,
315                                          catgets(_ttcatd, 7, 10,
316                                                  "%s: Found archive version %d, "
317                                                  "but expected version %d.\n"),
318                                          (char *)our_process_name, version,
319                                          CURRENT_ARCHIVE_VERSION );
320                                 return FALSE;
321                         }
322                         break;
323                     case SPEC:
324                         if (! spec.xdr(xdrs)) {
325                                 my_tt_release( mem_mark );
326                                 return FALSE;
327                         }
328                         if (dearchive_this_path( (char *)spec.path(),
329                                                    &paths_to_list ))
330                         {
331                                 Lstar_string_map_ptr m = new Lstar_string_map;
332
333                                 /*
334                                  * Insert it into this "map" just so that
335                                  * we can use the map to figure out if
336                                  * a given link counts under paths_to_list.
337                                  */
338                                 m->old_string_set( spec.id() );
339                                 m->extra_set( spec.path() );
340                                 spec_map->insert( m );
341                                 this_path = spec.path();
342                                 num_specs++;
343                                 if (verbosity > 1) {
344                                         spec.print( stdout );
345                                 }
346                         } else {
347                                 continue;
348                         }
349                         break;
350                     case ARCHIVE_END:
351                         break;
352                     case NO_KIND:
353                     default:
354                         fprintf( stderr,
355                                  catgets(_ttcatd, 7, 11,
356                                          "%s: found object of unknown kind "
357                                          "%d in archive.\n"),
358                                  (char *)our_process_name, (int)obj_kind );
359                         return FALSE;
360                 }
361                 if (    (last_path != this_path)
362                      || (obj_kind == ARCHIVE_END))
363                 {
364                         if (last_path_valid) {
365                                 if (obj_kind == SPEC) {
366                                         num_specs--;
367                                 } else if (obj_kind == SUN_LINK) {
368                                         num_links--;
369                                 }
370                                 printf( "%s %d %s\n",
371                                         (char *)last_path, num_specs,
372                                         (num_specs == 1 ? "spec" : "specs" ));
373                                 num_specs = 0;
374                                 num_links = 0;
375                                 if (obj_kind == SPEC) {
376                                         num_specs = 1;
377                                 } else if (obj_kind == SUN_LINK)  {
378                                         num_links = 1;
379                                 }
380                         }
381                         last_path = this_path;
382                         if (! last_path_valid) {
383                                 last_path_valid = TRUE;
384                         }
385                 }
386         } while (obj_kind != ARCHIVE_END);
387         my_tt_release( mem_mark );
388         return TRUE;
389
390 } /* pathlist_lstt_archive_list() */
391
392 /*
393  * path_lstt_archive() - Archive the specs on the given path. 
394  */
395 static bool_t
396 path_lstt_archive(
397         _Tt_string              path,
398         int                     verbosity,
399         XDR                    *xdrs )
400 {
401         _Tt_string_list        *specs;
402         Object_kind             obj_kind;
403         int                     num_specs_archived = 0;
404         int                     num_links_archived = 0;
405         bool_t                  val2return         = TRUE;
406
407         specs           = new _Tt_string_list;
408         note_err( tt_file_objects_query( (char *)path, gather_specs, NULL, specs ));
409         if (IS_TT_ERR(err_noted)) {
410                 delete specs;
411                 return TRUE;
412         }
413         while (! specs->is_empty()) {
414                 _Tt_string  spec = specs->top();
415                 Tt_status   tt_err;
416
417                 obj_kind = SPEC;
418                 specs->pop();
419                 if (! xdr_enum( xdrs, (enum_t *)&obj_kind )) {
420                         fprintf( stderr, "%s: ! xdr_enum()\n",
421                                  (char *)our_process_name );
422                         val2return = FALSE;
423                         break;
424                 }
425                 if (! spec_archive( (char *)spec, (char *)path, verbosity,
426                                     xdrs, &tt_err ))
427                 {
428                         val2return = FALSE;
429                         break;
430                 }
431                 num_specs_archived++;
432         }
433         if ((verbosity && num_specs_archived > 0 ) || (verbosity > 1)) {
434                 if (verbosity > 1) {
435                         fprintf( stderr, "\n" );
436                 }
437                 fprintf( stderr, "a %s: %d %s\n", (char *)path,
438                          num_specs_archived,
439                          ((num_specs_archived == 1) ? "spec" : "specs" ));
440         }
441         delete specs;
442         return val2return;
443
444 } /* path_lstt_archive() */
445
446
447 /*
448  * spec_archive() - Archive a spec onto the given XDR stream.
449  */
450 bool_t
451 spec_archive( char *id, char *path, int verbosity, XDR *xdrs, Tt_status *err )
452 {
453         _Tt_string      _path( path );
454         _Tt_string      _id( id );
455
456         *err = TT_OK;
457         if (xdrs->x_op == XDR_ENCODE) {
458                 Lstar_spec spec( _id, _path );
459
460                 *err = spec.read_self();
461                 if (IS_TT_ERR(*err)) {
462                         return FALSE;
463                 }
464                 if (! spec.xdr(xdrs)) {
465                         return FALSE;
466                 }
467                 if (verbosity > 1) {
468                         spec.print( stderr );
469                 }
470         } else {
471                 return FALSE;
472         }
473         return TRUE;
474
475 } /* spec_archive() */
476
477 /*
478  * spec_dearchive() - Recreate a spec that was archived on this XDR stream.
479  */
480 bool_t
481 spec_dearchive(
482         char          **old_spec_id_ptr,
483         char          **new_spec_id_ptr,
484         char          **path_as_archived,
485         Lstar_string_map_list_ptr renamings,
486         char           *where_to_create,
487         bool_t          preserve__props,
488         bool_t        (*dearchive_this_path)(char *, void *),
489         void           *context,
490         int             verbosity,
491         XDR            *xdrs,
492         Tt_status      *err )
493 {
494         _Tt_string      where( where_to_create );
495
496         *err = TT_OK;
497         *old_spec_id_ptr = NULL;
498         *new_spec_id_ptr = NULL;
499         *path_as_archived = NULL;
500         if (xdrs->x_op == XDR_ENCODE) {
501                 return FALSE;
502         } else if (xdrs->x_op == XDR_DECODE) {
503                 Lstar_spec spec;
504                 _Tt_string path;
505
506                 if (! spec.xdr(xdrs)) {
507                         return FALSE;
508                 }
509                 *old_spec_id_ptr = _tt_strdup( spec.id() );
510                 *path_as_archived = _tt_strdup( spec.path() );
511                 path = spec.path();
512                 if (    (dearchive_this_path == NULL)
513                      || (dearchive_this_path( (char *)path, context )))
514                 {
515                         _Tt_string _new_name = new_name( spec.path(),
516                                                          renamings );
517                         if (_new_name.len() > 0) {
518                                 if (verbosity > 2) {
519                                         fprintf( stderr, "%s => ",
520                                                  (char *)spec.path() );
521                                 }
522                                 spec.path_set( _new_name );
523                                 if (verbosity > 2) {
524                                         fprintf( stderr, "%s\n",
525                                                  (char *)spec.path() );
526                                 }
527                         }
528                         *new_spec_id_ptr =
529                                 spec.write_self( where, preserve__props, err );
530                         if (! IS_TT_ERR(*err) && (verbosity > 1)) {
531                                 spec.print( stdout );
532                         }
533                 }
534         }
535         return TRUE;
536
537 } /* spec_dearchive() */
538
539
540 /*
541  * dearchive_this_path() - Should we extract this <path> from its archive?
542  *
543  *      Returns true if *ppaths_to_extract is an empty list.
544  */
545 bool_t
546 dearchive_this_path( char *path, void *ppaths_to_extract )
547 {
548         _Tt_string_list_ptr     paths;
549         _Tt_string              _path( path );
550
551         if (ppaths_to_extract == NULL) {
552                 return TRUE;
553         }
554         paths = *(_Tt_string_list_ptr *)ppaths_to_extract;
555         if (paths->count() <= 0) {
556                 return TRUE;
557         }
558         return is_child_in( _path, paths );
559
560 } /* dearchive_this_path() */
561
562 /*
563  * gather_specs()
564  */
565 static Tt_filter_action
566 gather_specs( const char *spec_id, void *, void *specs )
567 {
568         _Tt_string id = spec_id;
569         ((_Tt_string_list *)specs)->push( id );
570         return TT_FILTER_CONTINUE;
571 }