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