572 lines
14 KiB
C
572 lines
14 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
//%% (c) Copyright 1993, 1994 Hewlett-Packard Company
|
|
//%% (c) Copyright 1993, 1994 International Business Machines Corp.
|
|
//%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
|
|
//%% (c) Copyright 1993, 1994 Novell, Inc.
|
|
//%% $XConsortium: tttar_api.C /main/4 1995/10/20 16:59:54 rswiston $
|
|
/*
|
|
* tttar_api.cc - ToolTalk object archiving interface functions.
|
|
*
|
|
* Copyright (c) 1990 by Sun Microsystems, Inc.
|
|
*
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#if defined(__osf__) || defined(linux) || defined(CSRG_BASED) || defined(sun)
|
|
#include <unistd.h>
|
|
#else
|
|
#ifndef USL
|
|
#include <osfcn.h>
|
|
#endif
|
|
#endif
|
|
#include <sys/param.h>
|
|
#include "api/c/api_api.h"
|
|
#include "api/c/tt_c.h"
|
|
#include "util/tt_path.h"
|
|
#include "util/tt_gettext.h"
|
|
#include "tttar_utils.h"
|
|
#include "tttar_file_utils.h"
|
|
#include "tttar_spec.h"
|
|
#include "tttar_api.h"
|
|
|
|
/*
|
|
* Type definitions
|
|
*/
|
|
|
|
|
|
/*
|
|
* Constants
|
|
*/
|
|
|
|
// Number of buckets in a hash table of interesting specs in an archive.
|
|
#define SPEC_MAP_SIZE 1000
|
|
|
|
/*
|
|
* Private functions
|
|
*/
|
|
static bool_t path_lstt_archive(
|
|
_Tt_string path,
|
|
int verbosity,
|
|
XDR *xdrs );
|
|
bool_t dearchive_this_path(
|
|
char *path, void *ppaths_to_extract );
|
|
static Tt_filter_action gather_specs( const char *spec_id, void *,
|
|
void *specs);
|
|
|
|
/*
|
|
* pathlist_lstt_archive() - Archive the LS/TT objects in the given paths.
|
|
*/
|
|
bool_t
|
|
pathlist_lstt_archive(
|
|
_Tt_string_list_ptr paths,
|
|
bool_t recurse,
|
|
bool_t follow_symlinks,
|
|
int verbosity,
|
|
XDR *xdrs )
|
|
{
|
|
_Tt_string_list_ptr realpaths2tar;
|
|
Object_kind obj_kind;
|
|
_Tt_string_list_ptr paths_copy(new _Tt_string_list);
|
|
_Tt_string_list_cursor path_cursor( paths );
|
|
while (path_cursor.next()) {
|
|
paths_copy->append( *path_cursor );
|
|
}
|
|
|
|
bool_t need_preliminary_pass = follow_symlinks && recurse;
|
|
realpaths2tar = realtrees( paths_copy, need_preliminary_pass );
|
|
|
|
obj_kind = VERSION_NUM;
|
|
int version = CURRENT_ARCHIVE_VERSION;
|
|
if ( (! xdr_enum( xdrs, (enum_t *)&obj_kind ))
|
|
|| (! xdr_int( xdrs, &version )))
|
|
{
|
|
fprintf( stderr, "%s: ! xdr_enum() || ! xdr_int()\n",
|
|
(char *)our_process_name );
|
|
return FALSE;
|
|
}
|
|
while (! paths_copy->is_empty()) {
|
|
_Tt_string_list_ptr children;
|
|
_Tt_string path( paths_copy->top() );
|
|
|
|
paths_copy->pop();
|
|
if (! path_lstt_archive( path, verbosity, xdrs ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (recurse) {
|
|
children = _tt_dir_entries( path, follow_symlinks );
|
|
children->append_destructive( paths_copy );
|
|
paths_copy = children;
|
|
}
|
|
}
|
|
obj_kind = ARCHIVE_END;
|
|
if (! xdr_enum( xdrs, (enum_t *)&obj_kind )) {
|
|
fprintf( stderr, "%s: ! xdr_enum()\n",
|
|
(char *)our_process_name );
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
|
|
} /* pathlist_lstt_archive() */
|
|
|
|
/*
|
|
* pathlist_lstt_dearchive() - Extract the LS/TT objects of the given paths.
|
|
* If no paths are given, extract everything in the archive.
|
|
*/
|
|
bool_t
|
|
pathlist_lstt_dearchive(
|
|
_Tt_string_list_ptr paths_to_extract,
|
|
Lstar_string_map_list_ptr renamings,
|
|
_Tt_string where_to_dearchive,
|
|
bool_t preserve__props,
|
|
int verbosity,
|
|
XDR *xdrs )
|
|
{
|
|
_Tt_string last_path;
|
|
char *this_path = NULL;
|
|
int num_specs = 0;
|
|
int num_links = 0;
|
|
bool_t last_path_valid = FALSE;
|
|
Object_kind obj_kind = NO_KIND;
|
|
Lstar_string_map_table_ptr spec_map;
|
|
int mem_mark = tt_mark();
|
|
|
|
spec_map = new Lstar_string_map_table(Lstar_string_map_old_string,
|
|
SPEC_MAP_SIZE );
|
|
do {
|
|
bool_t just_dearchived_spec = FALSE;
|
|
bool_t just_dearchived_link = FALSE;
|
|
|
|
if (! xdr_enum( xdrs, (enum_t *)&obj_kind )) {
|
|
fprintf( stderr,
|
|
catgets(_ttcatd, 7, 4,
|
|
"%s: Could not read object kind "
|
|
"from archive stream.\n"),
|
|
(char *)our_process_name );
|
|
return FALSE;
|
|
}
|
|
switch (obj_kind) {
|
|
case VERSION_NUM:
|
|
int version;
|
|
if (! xdr_int( xdrs, &version)) {
|
|
fprintf( stderr,
|
|
catgets(_ttcatd, 7, 5,
|
|
"%s: Could not read archive ver"
|
|
"sion from archive stream.\n"),
|
|
(char *)our_process_name );
|
|
return FALSE;
|
|
}
|
|
if (version != CURRENT_ARCHIVE_VERSION) {
|
|
fprintf( stderr,
|
|
catgets(_ttcatd, 7, 6,
|
|
"%s: Found archive version %d, "
|
|
"but expected version %d.\n"),
|
|
(char *)our_process_name, version,
|
|
CURRENT_ARCHIVE_VERSION );
|
|
return FALSE;
|
|
}
|
|
break;
|
|
case SPEC:
|
|
char *old_spec_id;
|
|
char *new_spec_id;
|
|
Tt_status err;
|
|
|
|
old_spec_id = NULL;
|
|
new_spec_id = NULL;
|
|
err = TT_OK;
|
|
|
|
if (! spec_dearchive( &old_spec_id, &new_spec_id,
|
|
&this_path, renamings,
|
|
(char *)where_to_dearchive,
|
|
preserve__props,
|
|
dearchive_this_path,
|
|
(void *)&paths_to_extract,
|
|
verbosity,
|
|
xdrs, &err ))
|
|
{
|
|
my_tt_release( mem_mark );
|
|
return FALSE;
|
|
}
|
|
if (new_spec_id != NULL) {
|
|
Lstar_string_map_ptr m = new Lstar_string_map;
|
|
|
|
m->old_string_set( old_spec_id );
|
|
m->new_string_set( new_spec_id );
|
|
m->extra_set( this_path );
|
|
spec_map->insert( m );
|
|
num_specs++;
|
|
just_dearchived_spec = TRUE;
|
|
}
|
|
break;
|
|
case ARCHIVE_END:
|
|
break;
|
|
case NO_KIND:
|
|
default:
|
|
fprintf( stderr,
|
|
catgets(_ttcatd, 7, 7,
|
|
"%s: found object of unknown kind "
|
|
"%d in archive.\n"),
|
|
(char *)our_process_name, (int)obj_kind );
|
|
return FALSE;
|
|
}
|
|
if (verbosity && ( (last_path != (const char *)this_path)
|
|
|| (obj_kind == ARCHIVE_END)))
|
|
{
|
|
if (last_path_valid) {
|
|
if (just_dearchived_spec) {
|
|
num_specs--;
|
|
} else if (just_dearchived_link) {
|
|
num_links--;
|
|
}
|
|
if (verbosity > 1) {
|
|
fprintf( stderr, "\n" );
|
|
}
|
|
if ( (num_specs > 0) || (num_links > 0)) {
|
|
fprintf( stderr, "x %s %d %s\n",
|
|
(char *)last_path, num_specs,
|
|
( num_specs == 1
|
|
? "spec" : "specs" ));
|
|
}
|
|
num_specs = 0;
|
|
num_links = 0;
|
|
if (just_dearchived_spec) {
|
|
num_specs = 1;
|
|
} else if (just_dearchived_link) {
|
|
num_links = 1;
|
|
}
|
|
}
|
|
last_path = this_path;
|
|
if (! last_path_valid) {
|
|
last_path_valid = TRUE;
|
|
}
|
|
}
|
|
} while (obj_kind != ARCHIVE_END);
|
|
my_tt_release( mem_mark );
|
|
return TRUE;
|
|
|
|
} /* pathlist_lstt_dearchive() */
|
|
|
|
/*
|
|
* pathlist_lstt_archive_list() - List the LS/TT objects of the given paths.
|
|
* If no paths are given, list everything in the archive.
|
|
*/
|
|
bool_t
|
|
pathlist_lstt_archive_list(
|
|
_Tt_string_list_ptr paths_to_list,
|
|
int verbosity,
|
|
XDR *xdrs )
|
|
{
|
|
_Tt_string last_path;
|
|
_Tt_string this_path;
|
|
int num_specs = 0;
|
|
int num_links = 0;
|
|
bool_t last_path_valid = FALSE;
|
|
Object_kind obj_kind = NO_KIND;
|
|
Lstar_string_map_table_ptr spec_map;
|
|
int mem_mark = tt_mark();
|
|
|
|
spec_map = new Lstar_string_map_table(Lstar_string_map_old_string,
|
|
SPEC_MAP_SIZE );
|
|
do {
|
|
Lstar_spec spec;
|
|
|
|
if (! xdr_enum( xdrs, (enum_t *)&obj_kind )) {
|
|
fprintf( stderr,
|
|
catgets(_ttcatd, 7, 8,
|
|
"%s: Could not read object kind "
|
|
"from archive stream.\n"),
|
|
(char *)our_process_name );
|
|
return FALSE;
|
|
}
|
|
switch (obj_kind) {
|
|
case VERSION_NUM:
|
|
int version;
|
|
if (! xdr_int( xdrs, &version)) {
|
|
fprintf( stderr,
|
|
catgets(_ttcatd, 7, 9,
|
|
"%s: Could not read archive ver"
|
|
"sion from archive stream.\n"),
|
|
(char *)our_process_name );
|
|
return FALSE;
|
|
}
|
|
if (version != CURRENT_ARCHIVE_VERSION) {
|
|
fprintf( stderr,
|
|
catgets(_ttcatd, 7, 10,
|
|
"%s: Found archive version %d, "
|
|
"but expected version %d.\n"),
|
|
(char *)our_process_name, version,
|
|
CURRENT_ARCHIVE_VERSION );
|
|
return FALSE;
|
|
}
|
|
break;
|
|
case SPEC:
|
|
if (! spec.xdr(xdrs)) {
|
|
my_tt_release( mem_mark );
|
|
return FALSE;
|
|
}
|
|
if (dearchive_this_path( (char *)spec.path(),
|
|
&paths_to_list ))
|
|
{
|
|
Lstar_string_map_ptr m = new Lstar_string_map;
|
|
|
|
/*
|
|
* Insert it into this "map" just so that
|
|
* we can use the map to figure out if
|
|
* a given link counts under paths_to_list.
|
|
*/
|
|
m->old_string_set( spec.id() );
|
|
m->extra_set( spec.path() );
|
|
spec_map->insert( m );
|
|
this_path = spec.path();
|
|
num_specs++;
|
|
if (verbosity > 1) {
|
|
spec.print( stdout );
|
|
}
|
|
} else {
|
|
continue;
|
|
}
|
|
break;
|
|
case ARCHIVE_END:
|
|
break;
|
|
case NO_KIND:
|
|
default:
|
|
fprintf( stderr,
|
|
catgets(_ttcatd, 7, 11,
|
|
"%s: found object of unknown kind "
|
|
"%d in archive.\n"),
|
|
(char *)our_process_name, (int)obj_kind );
|
|
return FALSE;
|
|
}
|
|
if ( (last_path != this_path)
|
|
|| (obj_kind == ARCHIVE_END))
|
|
{
|
|
if (last_path_valid) {
|
|
if (obj_kind == SPEC) {
|
|
num_specs--;
|
|
} else if (obj_kind == SUN_LINK) {
|
|
num_links--;
|
|
}
|
|
printf( "%s %d %s\n",
|
|
(char *)last_path, num_specs,
|
|
(num_specs == 1 ? "spec" : "specs" ));
|
|
num_specs = 0;
|
|
num_links = 0;
|
|
if (obj_kind == SPEC) {
|
|
num_specs = 1;
|
|
} else if (obj_kind == SUN_LINK) {
|
|
num_links = 1;
|
|
}
|
|
}
|
|
last_path = this_path;
|
|
if (! last_path_valid) {
|
|
last_path_valid = TRUE;
|
|
}
|
|
}
|
|
} while (obj_kind != ARCHIVE_END);
|
|
my_tt_release( mem_mark );
|
|
return TRUE;
|
|
|
|
} /* pathlist_lstt_archive_list() */
|
|
|
|
/*
|
|
* path_lstt_archive() - Archive the specs on the given path.
|
|
*/
|
|
static bool_t
|
|
path_lstt_archive(
|
|
_Tt_string path,
|
|
int verbosity,
|
|
XDR *xdrs )
|
|
{
|
|
_Tt_string_list *specs;
|
|
Object_kind obj_kind;
|
|
int num_specs_archived = 0;
|
|
int num_links_archived = 0;
|
|
bool_t val2return = TRUE;
|
|
|
|
specs = new _Tt_string_list;
|
|
note_err( tt_file_objects_query( (char *)path, gather_specs, NULL, specs ));
|
|
if (IS_TT_ERR(err_noted)) {
|
|
delete specs;
|
|
return TRUE;
|
|
}
|
|
while (! specs->is_empty()) {
|
|
_Tt_string spec = specs->top();
|
|
Tt_status tt_err;
|
|
|
|
obj_kind = SPEC;
|
|
specs->pop();
|
|
if (! xdr_enum( xdrs, (enum_t *)&obj_kind )) {
|
|
fprintf( stderr, "%s: ! xdr_enum()\n",
|
|
(char *)our_process_name );
|
|
val2return = FALSE;
|
|
break;
|
|
}
|
|
if (! spec_archive( (char *)spec, (char *)path, verbosity,
|
|
xdrs, &tt_err ))
|
|
{
|
|
val2return = FALSE;
|
|
break;
|
|
}
|
|
num_specs_archived++;
|
|
}
|
|
if ((verbosity && num_specs_archived > 0 ) || (verbosity > 1)) {
|
|
if (verbosity > 1) {
|
|
fprintf( stderr, "\n" );
|
|
}
|
|
fprintf( stderr, "a %s: %d %s\n", (char *)path,
|
|
num_specs_archived,
|
|
((num_specs_archived == 1) ? "spec" : "specs" ));
|
|
}
|
|
delete specs;
|
|
return val2return;
|
|
|
|
} /* path_lstt_archive() */
|
|
|
|
|
|
/*
|
|
* spec_archive() - Archive a spec onto the given XDR stream.
|
|
*/
|
|
bool_t
|
|
spec_archive( char *id, char *path, int verbosity, XDR *xdrs, Tt_status *err )
|
|
{
|
|
_Tt_string _path( path );
|
|
_Tt_string _id( id );
|
|
|
|
*err = TT_OK;
|
|
if (xdrs->x_op == XDR_ENCODE) {
|
|
Lstar_spec spec( _id, _path );
|
|
|
|
*err = spec.read_self();
|
|
if (IS_TT_ERR(*err)) {
|
|
return FALSE;
|
|
}
|
|
if (! spec.xdr(xdrs)) {
|
|
return FALSE;
|
|
}
|
|
if (verbosity > 1) {
|
|
spec.print( stderr );
|
|
}
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
|
|
} /* spec_archive() */
|
|
|
|
/*
|
|
* spec_dearchive() - Recreate a spec that was archived on this XDR stream.
|
|
*/
|
|
bool_t
|
|
spec_dearchive(
|
|
char **old_spec_id_ptr,
|
|
char **new_spec_id_ptr,
|
|
char **path_as_archived,
|
|
Lstar_string_map_list_ptr renamings,
|
|
char *where_to_create,
|
|
bool_t preserve__props,
|
|
bool_t (*dearchive_this_path)(char *, void *),
|
|
void *context,
|
|
int verbosity,
|
|
XDR *xdrs,
|
|
Tt_status *err )
|
|
{
|
|
_Tt_string where( where_to_create );
|
|
|
|
*err = TT_OK;
|
|
*old_spec_id_ptr = NULL;
|
|
*new_spec_id_ptr = NULL;
|
|
*path_as_archived = NULL;
|
|
if (xdrs->x_op == XDR_ENCODE) {
|
|
return FALSE;
|
|
} else if (xdrs->x_op == XDR_DECODE) {
|
|
Lstar_spec spec;
|
|
_Tt_string path;
|
|
|
|
if (! spec.xdr(xdrs)) {
|
|
return FALSE;
|
|
}
|
|
*old_spec_id_ptr = _tt_strdup( spec.id() );
|
|
*path_as_archived = _tt_strdup( spec.path() );
|
|
path = spec.path();
|
|
if ( (dearchive_this_path == NULL)
|
|
|| (dearchive_this_path( (char *)path, context )))
|
|
{
|
|
_Tt_string _new_name = new_name( spec.path(),
|
|
renamings );
|
|
if (_new_name.len() > 0) {
|
|
if (verbosity > 2) {
|
|
fprintf( stderr, "%s => ",
|
|
(char *)spec.path() );
|
|
}
|
|
spec.path_set( _new_name );
|
|
if (verbosity > 2) {
|
|
fprintf( stderr, "%s\n",
|
|
(char *)spec.path() );
|
|
}
|
|
}
|
|
*new_spec_id_ptr =
|
|
spec.write_self( where, preserve__props, err );
|
|
if (! IS_TT_ERR(*err) && (verbosity > 1)) {
|
|
spec.print( stdout );
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
} /* spec_dearchive() */
|
|
|
|
|
|
/*
|
|
* dearchive_this_path() - Should we extract this <path> from its archive?
|
|
*
|
|
* Returns true if *ppaths_to_extract is an empty list.
|
|
*/
|
|
bool_t
|
|
dearchive_this_path( char *path, void *ppaths_to_extract )
|
|
{
|
|
_Tt_string_list_ptr paths;
|
|
_Tt_string _path( path );
|
|
|
|
if (ppaths_to_extract == NULL) {
|
|
return TRUE;
|
|
}
|
|
paths = *(_Tt_string_list_ptr *)ppaths_to_extract;
|
|
if (paths->count() <= 0) {
|
|
return TRUE;
|
|
}
|
|
return is_child_in( _path, paths );
|
|
|
|
} /* dearchive_this_path() */
|
|
|
|
/*
|
|
* gather_specs()
|
|
*/
|
|
static Tt_filter_action
|
|
gather_specs( const char *spec_id, void *, void *specs )
|
|
{
|
|
_Tt_string id = spec_id;
|
|
((_Tt_string_list *)specs)->push( id );
|
|
return TT_FILTER_CONTINUE;
|
|
}
|