/* swheader.c  --  Routines for searching the sw_parser output.
 * $Id: swheader.c,v 1.58 2000/10/14 19:50:38 jhl Exp jhl $
 */

/*
   Copyright (C) 1998-2004  James H. Lowe, Jr.  <jhlowe@acm.org>
   All Rights Reserved.
  
   COPYING TERMS AND CONDITIONS
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
 */


#include "swuser_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <tar.h>

#include "taru.h"
#include "strob.h"
#include "cplob.h"
#include "uxfio.h"
#include "swlib.h"
#include "uinfile.h"
#include "swheader.h"
#include "swheaderline.h"
#include "uinfile.h"
#include "cpiohdr.h"
#include "swverid.h"
#include "swparse.h"

#include "debug_config.h"
#ifdef SWHEADERNEEDDEBUG
#define SWHEADER_E_DEBUG(format) SWBISERROR("SWHEADER DEBUG: ", format)
#define SWHEADER_E_DEBUG2(format, arg) SWBISERROR2("SWHEADER DEBUG: ", format, arg)
#define SWHEADER_E_DEBUG3(format, arg, arg1) SWBISERROR3("SWHEADER DEBUG: ", format, arg, arg1)
#else
#define SWHEADER_E_DEBUG(arg)
#define SWHEADER_E_DEBUG2(arg, arg1)
#define SWHEADER_E_DEBUG3(arg, arg1, arg2)
#endif /* SWHEADERNEEDDEBUG */


#define NEWLINE_LEN 1

static char * swheader_goto_c_next_line (void * vheader, 
				int * output_line_offset, int peek_only);
static void swheader__reset(SWHEADER * swheader);


static char *
swheader_goto_c_next_line (void * vheader, int * output_line_offset,
					int peek_only)
{
	SWHEADER * swheader=(SWHEADER*)vheader;
	char * ih=swheader->image_head_;
	char *keyw, *p;
	int n, type;
	
	/* Interface:
	==============
	output_line_offset *output_line_offset	Action
	------------------  ------------------     --------
	NULL		   not applicable	reset	
	not NULL	   INT_MAX		return swheader->image_head_;	
	not NULL		<0	return C address of line at offset:
							-(*output_line_offset)
	*/

	if (!output_line_offset){ 
		swheader__reset(swheader);
		return (char*)(NULL);
	}
	
	if (*output_line_offset == INT_MAX){
		return ih;
	}
        
	if (*output_line_offset < 0) {
		return ih + (-(*output_line_offset));	
	}	
	
	/* Return next line
	 */
	
	
	/* if type 'F' (i.e File name reference), then
	    set value to next line and return.  */

	type = swheaderline_get_type (ih+(*output_line_offset));
	if (type == 'F') {
		p=strchr(ih+(*output_line_offset), '\n')+NEWLINE_LEN;
		if (p) {
			*output_line_offset=p-swheader->image_head_;
		}
		return p;	
	}


	/* Must be a attribute or object keyword. */

	keyw = swheaderline_get_keyword(ih+(*output_line_offset));
	if (!keyw)
		return NULL;
	n = swheaderline_get_value_length(ih+(*output_line_offset));
        if (type == 'A') n++; /* add the space between the value and keyword*/

	/* detecting the last line requires that there be a NULL 
	   after the end of the last line */

	/* assumes newline is 1 char long */

	p = keyw + strlen(keyw) + n + NEWLINE_LEN;

	/* next char will be a '0' or '-' or NUL.
	   if NUL then we're at the last line.
	  '0' and '-' ar possible first chars of a header line.  */

	if (*p == '\0' && peek_only == 0) {
		*output_line_offset=-1;
	}	
	if (*p == '\0') {
		return (char *) (NULL);
	}	
	if (peek_only == 0) {
		*output_line_offset=p-swheader->image_head_;
	}
	return p;
}

static void
swheader__reset(SWHEADER * swheader)
{
	swheader->current_offset_=0;
	*(swheader->current_offset_p_)=0;
}

/* -------------------------------------------------------------------*/
/* ------------------ Public Functions ------------------------------*/

void
swheader_store_state(SWHEADER * header)
{
	header->save_current_offset_p_ = header->current_offset_p_;
	header->save_current_offset_ = header->current_offset_;
	if (header->current_offset_p_)
		header->save_current_offset_v_ = *(header->current_offset_p_);
}

void
swheader_restore_state(SWHEADER * header)
{
	header->current_offset_p_ = header->save_current_offset_p_;
	header->current_offset_ = header->save_current_offset_;
	if (header->current_offset_p_)
		*(header->current_offset_p_) = header->save_current_offset_v_;
}

SWHEADER *
swheader_open(char* (*f_goto_next)(void * , int* , int), void * image_object)
{
	int i;
	SWHEADER *swheader=(SWHEADER *)malloc(sizeof(SWHEADER));
	if (!swheader)
		return swheader;
	
	/* swheader->length_ = 0; */

	for (i=0; i<=SWHEADER_IMAGE_STACK_LEN; i++)
			swheader->image_object_stack_[i]=(void*)(NULL);

	if (image_object){
		swheader_set_image_object(swheader, image_object, 0);
		swheader->image_object_=image_object;
	}else{
		swheader_set_image_object(swheader, (void*)(swheader), 0);
		swheader->image_object_=(void*)swheader;
	}	

	swheader->f_goto_next_=f_goto_next;
	swheader->current_offset_p_=&(swheader->current_offset_);
	swheader->current_offset_=0;
	swheader->image_head_ = NULL;
        if (!swheader->f_goto_next_)
		swheader_set_iter_function(swheader, 
				swheader_goto_c_next_line);
	return swheader;
}

o__inline__
void
swheader_close(SWHEADER * swheader)
{
	if (swheader != NULL) swbis_free(swheader);
}

void
swheader_reset(SWHEADER * swheader)
{
	swheader__reset(swheader);
	if (swheader->f_goto_next_ != swheader_goto_c_next_line){	
		/* If here, then the collection is a C++ collection. */
		
		/* due to bug (probably) in switer.cxx, 
		 * read through the collection.  This
		 * will instantiate the switer objects.
		 */
		while(swheader_f_goto_next(swheader));
	}
	swheader__reset(swheader);
	(*(swheader->f_goto_next_))(swheader->image_object_, NULL, 
							SWHEADER_GET_NEXT);
}

char *
swheader_f_goto_next(SWHEADER * swheader)
{
	char * ret;
	ret =  (*(swheader->f_goto_next_))(swheader->image_object_,
				swheader_get_current_offset_p(swheader),
						SWHEADER_GET_NEXT);
	return ret;
}


/*
 *  swheader_goto_next_line
 *	goto next line relative to the line pointed to by 
 *	*(output_line_offset).  A pointer to the next line is 
 *	returned and output_line_offset is set to this line.
 * 
 *	Other Functionality provided by the interface:
 *		Reset:	
 *			if output_line_offset==NULL 
 *		
 *		Return first line: 
 *			if (*output_line_offset == INT_MAX) 
 * 
 *		 
 *		Convert offset to char pointer without any side effects:
 *			if (*output_line_offset < 0)
 */
o__inline__
char *
swheader_goto_next_line(void * vheader, int * output_line_offset,
						int peek_only)
{
	char * ret;
	ret = (*(((SWHEADER*)(vheader))->f_goto_next_))
				(((SWHEADER*)(vheader))->image_object_,
						output_line_offset, peek_only);
	return ret;
}


char *
swheader_get_current_line(SWHEADER * swheader)
{
		int i;
		char * p;
		
		SWHEADER_E_DEBUG("");
		i = -swheader_get_current_offset(swheader);
		SWHEADER_E_DEBUG2("current offset is %d", i);
		p = (*(swheader->f_goto_next_))
				(swheader->image_object_, &i,
							SWHEADER_PEEK_NEXT);

		if (!p) {
			SWHEADER_E_DEBUG("returning NULL");
			return NULL;
		} else {
			SWHEADER_E_DEBUG3("returning non-NULL p=%p value=[%s]", p, p);
			return p;
		}
}

void
swheader_set_iter_function(SWHEADER * swheader,
				char * (*fc)(void *, int *, int))
{
	SWHEADER_E_DEBUG("");
	swheader->f_goto_next_ = fc;
}

o__inline__
int
swheader_set_image_object(SWHEADER * swheader, void * image, int index)
{
	int i=0;
	SWHEADER_E_DEBUG("");
	if (index < 0){
		while (swheader->image_object_stack_[i]) i++;
		if (i >= SWHEADER_IMAGE_STACK_LEN)
			return -1;
	} else {
		i=index;
	}
	swheader->image_object_stack_[i]=image;
	return i;
}

o__inline__
void
swheader_set_image_object_active(SWHEADER * swheader, int index)
{
	SWHEADER_E_DEBUG("");
	swheader->image_object_=swheader->image_object_stack_[index];
}

o__inline__
void
swheader_set_image_head(SWHEADER * swheader, void * image)
{
	SWHEADER_E_DEBUG("");
	swheader->image_head_=image;
}

o__inline__
void
swheader_set_current_offset(SWHEADER * swheader, int n)
{
	/* swheader->current_offset_=n; */
	swheader_set_current_offset_p_value(swheader, n);
}

o__inline__
void
swheader_set_current_offset_p_value(SWHEADER * swheader, int n)
{
	*(swheader->current_offset_p_)=n;
}

o__inline__
void
swheader_set_current_offset_p(SWHEADER * swheader, int *n)
{
	if(!n)
		swheader->current_offset_p_=&(swheader->current_offset_);
	else
		swheader->current_offset_p_=n;
}

/* void * */
/* (char * (*)(void *, int*)) */
void * 
swheader_get_iter_function(SWHEADER * swheader)
{
	return (void*)(swheader->f_goto_next_);
}

/*
o__inline__
void
swheader_set_image_length(SWHEADER * swheader, int len)
{
	swheader->length_ = len;
}


o__inline__
int
swheader_get_image_length(SWHEADER * swheader)
{
	return swheader->length_;
}
*/

o__inline__
int *
swheader_get_current_offset_p(SWHEADER * swheader)
{
	return swheader->current_offset_p_;
}

o__inline__
int
swheader_get_current_offset(SWHEADER * swheader)
{
	return *(swheader->current_offset_p_);
}


char *
swheader_get_image_head(SWHEADER * swheader)
{
	int i=INT_MAX;
	return (*(swheader->f_goto_next_))(swheader->image_object_,
						&i, SWHEADER_GET_NEXT);
}


/*
 *  swheader_get_next_object():
 *
 *  Gets next object that meets specified level constraints.
 *  relative_level_* refers to  level numbers as seen in the sw_parse()
 *  output, they are inclusive. They are relative to the level of `image'
 *
 *  To disable level test, use relative_level_min=UCHAR_MAX and
 *  relative_level_max=UCHAR_MAX.
 *
 *  To get next object at same level, use relative_level_min=0 and
 *  relative_level_max=0.
 *
 *  To get all objects in the object `image', use relative_level_min=0 and
 *  relative_level_max=UCHAR_MAX.
 *
*/
char *
swheader_get_next_object(SWHEADER * swheader , int relative_level_min,
						int relative_level_max)
{
	char *next_line;
	int object_level=0;
	int current_relative_level;
        
	SWHEADER_E_DEBUG("");
	next_line=swheader_goto_next_line((void *)swheader,
			swheader_get_current_offset_p(swheader), 
				SWHEADER_GET_NEXT);
	while (next_line) {
		SWHEADER_E_DEBUG("");
		current_relative_level = swheaderline_get_level(next_line) -
								object_level; 
		if (swheaderline_get_type(next_line) == SWPARSE_MD_TYPE_OBJ) {
			if (relative_level_min == UCHAR_MAX && 
					relative_level_max == UCHAR_MAX) {
				SWHEADER_E_DEBUG("");
				return next_line;
			} else if ( 
				current_relative_level < relative_level_min ||
				current_relative_level > relative_level_max) {
				SWHEADER_E_DEBUG("tested NULL");
				return NULL;
			} else if (
				current_relative_level >= relative_level_min &&
				current_relative_level <= relative_level_max) {
				SWHEADER_E_DEBUG("");
				return next_line;
			} 
		}			
		next_line=swheader_goto_next_line((void *)swheader,
				swheader_get_current_offset_p(swheader),
							SWHEADER_GET_NEXT);
	}
	SWHEADER_E_DEBUG("terminating NULL");
	return NULL;
}

SWVERID *
swheader_generate_swverid(SWHEADER * swheader, char * object_line)
{
	int len;
	SWVERID * swverid;
	char *next_attr, *keyw, *value, *object_keyword;
	int object_offset=swheader_get_current_offset(swheader);
	
	/* make the identity object */
	if (object_line == (char*)(NULL))
		return (SWVERID*)(NULL);
	object_keyword = swheaderline_get_keyword(object_line);
	swverid = swverid_open(object_keyword, (char*)NULL);

	while ((next_attr = swheader_get_next_attribute(swheader))) {
		value = swheaderline_get_value(next_attr, &len);
		keyw = swheaderline_get_keyword(next_attr);
		if (!keyw || !value) {
			fprintf(stderr,
				"error in swheader_generate_swverid.\n");	
			swheader_set_current_offset_p_value(swheader,
						object_offset);
			swverid_close(swverid);
			return (SWVERID*)(NULL);
		}
		if (swverid_add_attribute(swverid,
				object_keyword, keyw, value) < 0) {
			swverid_close(swverid);
			return (SWVERID*)(NULL);
		}
	}
	swheader_set_current_offset_p_value(swheader, object_offset);
	return swverid;
}

char *
swheader_get_single_attribute_value(SWHEADER * swheader, char *keyword)
{
        char * line;
        char * value;
	int current_file_offset;
	current_file_offset = swheader_get_current_offset(swheader);
	line = swheader_get_attribute_in_object(swheader, keyword, NULL, NULL);
	if (!line) return line;
        value = swheaderline_get_value(line, NULL);
	swheader_set_current_offset(swheader, current_file_offset);
        return value;
}

/*
* Deprecated 
*/
char *
swheader_get_attribute_single_value(SWHEADER *swheader,
					char *attribute_keyword) {
	int multi;
	char **list;
	char **pp;
	char * ret=(char*)(NULL);
	
	SWHEADER_E_DEBUG("");
	list = swheader_get_attribute_list(swheader,
					attribute_keyword, &multi);
	pp = list;

	if (!list) return (char*)(NULL);

	/* return the last item in the list. */	

	while (*pp) {
		/* if (ret) swbis_free(ret); */
		ret=*pp;
		pp++;
	}

	/* FIXME memory leak */
	/* swbis_free(list); */
	return ret;
}

/*
 *  swheader_get_attribute_list
 *     returns a null terminated array of strings.  Each string
 *     is new storage and may be freed with free().  The pointer
 *     list vector may be freed with free() as well.
 */
char **
swheader_get_attribute_list(SWHEADER *swheader,
			char *attribute_keyword, int *multi_line)
{
	struct swsdflt_defaults *swd;
	char *line, *keyw, *headerline, **ret;
	CPLOB * cplob_obj;
	int object_offset=swheader_get_current_offset(swheader);
	
	headerline=swheader_get_current_line(swheader);
	if (swheaderline_get_type(headerline) != SWPARSE_MD_TYPE_OBJ) {
		return (char**)NULL;
	}

	/*
	* keyw is the object keyword.
	*/
	keyw=swheaderline_get_keyword(headerline);

	/*
	* Determine if this is a multi line attribute.
	*/
	if (multi_line) {
		swd=swsdflt_return_entry(keyw, attribute_keyword);
		if (swd == NULL) {
			/* *multi_line=(enum swsdflt_value_type)
							(sdf_single_value);
			*/
			*multi_line = 0;
		} else {
			if (swsdflt_get_value_type(swd) == 
				(enum swsdflt_value_type)(sdf_single_value)) {
				*multi_line = 0;
			} else {
				*multi_line = 1;
			}
		}
	}

	cplob_obj=cplob_open(2);
				/* initialize the null terminated array */
	cplob_add_nta(cplob_obj, (char*)(NULL));
	while ((line=swheader_get_next_attribute(swheader))){
		keyw = swheaderline_get_keyword(line);
		if (!strcmp(attribute_keyword, keyw)) {
			 cplob_add_nta(cplob_obj, line);
		}
	}
	ret = cplob_release(cplob_obj);
	swheader_set_current_offset_p_value(swheader, object_offset);
	return ret;
}


/*
* Get next attribute in current object.
*/

char *
swheader_get_next_attribute(SWHEADER * swheader)
{
	static int att_count=0;
	char * currentline;
        char * nextline;
	
	SWHEADER_E_DEBUG("");
        nextline=swheader_goto_next_line((void *)swheader,
		swheader_get_current_offset_p(swheader),
				SWHEADER_PEEK_NEXT);
	currentline=swheader_get_current_line(swheader);
	
	if (!currentline) {
		att_count=0;
		SWHEADER_E_DEBUG("returning NULL loc 0");
		return (char*)(NULL);
	} else if ((swheaderline_get_type(currentline) == 
					SWPARSE_MD_TYPE_OBJ) && 
						att_count) {
		att_count=0;
		SWHEADER_E_DEBUG("returning NULL loc 1");
		return (char*)(NULL);
	} else {
		if (
		!nextline || 
		(swheaderline_get_type(nextline) == SWPARSE_MD_TYPE_OBJ)) {
			att_count=0;
			SWHEADER_E_DEBUG("returning NULL loc 2");
			return (char*)(NULL);
		}
		att_count++;
        	swheader_f_goto_next(swheader); 
		SWHEADER_E_DEBUG2("returning next line [%s]", nextline);
		return nextline;
	}
}

char *
swheader_get_object(SWHEADER * swheader, SWVERID * swverid)
{
	char * next_line;
	SWVERID *t_swverid = NULL;
	int object_offset;
	Swverid_Cmp_Code comparison_result;

	SWHEADER_E_DEBUG("");
	/* step to first object */
	
	next_line=swheader_get_current_line(swheader);
	if (!next_line)
		return NULL;
	while (
		next_line && 
		(swheaderline_get_type(next_line) != SWPARSE_MD_TYPE_OBJ))
		next_line=swheader_f_goto_next(swheader);

	do {
		object_offset=swheader_get_current_offset(swheader);
		if ((t_swverid = swheader_generate_swverid(swheader, next_line)) ==
							 (SWVERID*)(NULL)){
			fprintf(stderr,
	"swheader_get_object: error returned by swheader_generate_swverid.\n");	
			return (char *)NULL;
		}
		comparison_result = swverid_compare(swverid, t_swverid);
		if (comparison_result==SWVERID_CMP_EQ) {
			swverid_close(t_swverid);
			t_swverid = NULL;
			swheader_set_current_offset_p_value(swheader,
								object_offset);
			return next_line;
		}
		swverid_close(t_swverid);
		t_swverid = NULL;
	} while ((next_line = swheader_get_next_object(swheader,
					(int)(UCHAR_MAX), (int)UCHAR_MAX)));
	if (t_swverid) swverid_close(t_swverid);
	swheader_set_current_offset_p_value(swheader, object_offset);
	return (char*)NULL;
}

char *
swheader_get_object_by_tag(SWHEADER * swheader, 
					char *object_keyword,
						char *idtag)
{
	SWVERID *swverid = swverid_open(object_keyword, (char*)(NULL));
	char *ret;

	SWHEADER_E_DEBUG("");
	swverid_set_tag(swverid, "tag", idtag);
	swverid_set_comparison_code(swverid, SWVERID_CMP_EQ);
	ret = swheader_get_object(swheader, swverid);
	swverid_close(swverid);
	return ret;
}

int
swheader_get_object_offset_by_control_directory(SWHEADER * swheader,  STRAR * pairs)
{
	char * next_line;
	int object_offset = 0;  /* FIXME */
	char * control_directory;
	char * tag;

	/*
	 * first handle a minimal package.
	 * If control_dir is 0 length, then there can only be one 
	 * product and one fileset.
	 */	



	SWHEADER_E_DEBUG("");
	/* step to first object */
	
	next_line=swheader_get_current_line(swheader);
	if (!next_line)
		return -1;

	/*
	 * goto the first object
	 */
	while (
		next_line && 
		(swheaderline_get_type(next_line) != SWPARSE_MD_TYPE_OBJ))
	{
		next_line=swheader_f_goto_next(swheader);
	}

	/*
	 * Loop thru the objects
	 */	
	do {

		control_directory = swheader_get_single_attribute_value(swheader, SW_A_control_directory);

	} while ((next_line = swheader_get_next_object(swheader,
					(int)(UCHAR_MAX), (int)UCHAR_MAX)));

	swheader_set_current_offset_p_value(swheader, object_offset);
	return -1;
}

char *
swheader_raw_get_attribute_in_object(SWHEADER * swheader, char *keyword)
{
	char *line;
	char *keyw;
	
	SWHEADER_E_DEBUG("");
	line = swheader_get_next_attribute(swheader);
	while(line) {
		keyw = swheaderline_get_keyword(line);
		if (strcmp(keyw, keyword) == 0) {
			return line;
		}
		line = swheader_get_next_attribute(swheader);
	}
	return (char*)NULL;
}


char *
swheader_get_attribute_in_object(SWHEADER * swheader, char *keyword,
				char * object_keyword, int * is_multi_value)
{
	int multi_line;
	struct swsdflt_defaults *swd;
	char * line, *prevline;
	
	SWHEADER_E_DEBUG("");
	if (object_keyword) {
		swd=swsdflt_return_entry(object_keyword, keyword);
		if (swd == NULL) {
			multi_line = 
			(enum swsdflt_value_type)(sdf_single_value);
		} else {
			multi_line = swsdflt_get_value_type(swd);
		}
	} else {
		multi_line = (enum swsdflt_value_type)(sdf_single_value);
	}

	if (multi_line == (enum swsdflt_value_type)(sdf_single_value)) {
		/*
		* single value, return the last one.
		*/
		if (is_multi_value) *is_multi_value = 0;
		line = swheader_raw_get_attribute_in_object(swheader, keyword);
		prevline = line;
		while (line) {
			line = swheader_raw_get_attribute_in_object(swheader,
								keyword);
			if (line) prevline = line;
		}
		return prevline;
	} else {
		/*
		* multi value attribute.
		*/
		if (is_multi_value) *is_multi_value = 1;
		line = swheader_raw_get_attribute_in_object(swheader,
								keyword);
		return line;
	}
}

int
swheader_fileobject2filehdr(SWHEADER * fileheader, struct new_cpio_header * file_hdr)
{
	char * attr;
	char * keyword;
	char * value;
	int len;
	int ret;
	int info_filetype = 0;
	int tartype = 0;
	mode_t modet;
	uid_t uid;
	gid_t gid;
	char did_uname = 0;
	char did_gname = 0;
	char did_gid = 0;
	char did_uid = 0;
	char did_mtime = 0;
	char did_mode = 0;
	char did_link_source = 0;
	char did_size = 0;
	char did_major = 0;
	char did_minor = 0;
	char did_type = 0;

	taru_init_header(file_hdr);

/*JL fprintf(stderr, ">> object start\n"); */
	while((attr=swheader_get_next_attribute(fileheader))) {
		keyword = swheaderline_get_keyword(attr);
		value = swheaderline_get_value(attr, &len);
/*JL fprintf(stderr, "%s = [%s]\n", keyword, value); */

		if (strcmp(keyword, "mode") == 0) {
			file_hdr->c_mode = 0;
			taru_otoul(value, &(file_hdr->c_mode));
			file_hdr->c_mode = file_hdr->c_mode & 07777;
			(file_hdr->usage_maskM) |= TARU_UM_MODE;
		} else if (strcmp(keyword, "size") == 0) {
			file_hdr->c_filesize = (unsigned long)atol(value);		
			did_size = 1;
		} else if (strcmp(keyword, "path") == 0) {
			ahsStaticSetTarFilename(file_hdr, value);
		} else if (strcmp(keyword, "uid") == 0) {
			file_hdr->c_uid = (unsigned long)atol(value);		
			(file_hdr->usage_maskM) |= TARU_UM_UID;
			did_uid = 1;
		} else if (strcmp(keyword, "gid") == 0) {
			file_hdr->c_gid = (unsigned long)atol(value);		
			(file_hdr->usage_maskM) |= TARU_UM_GID;
			did_gid = 1;
		} else if (strcmp(keyword, "link_source") == 0) {
			ahsStaticSetTarLinkname(file_hdr, value);
			did_link_source = 1;
		} else if (strcmp(keyword, "owner") == 0) {
			ahsStaticSetTarUsername(file_hdr, value);
			did_uname = 1;
			(file_hdr->usage_maskM) |= TARU_UM_OWNER;
		} else if (strcmp(keyword, "group") == 0) {
			ahsStaticSetTarGroupname(file_hdr, value);
			did_gname = 1;
			(file_hdr->usage_maskM) |= TARU_UM_GROUP;
		} else if (strcmp(keyword, "mtime") == 0) {
			file_hdr->c_mtime = strtoul(value, (char**)NULL, 10);
			did_mtime = 1;
			(file_hdr->usage_maskM) |= TARU_UM_MTIME;
		} else if (strcmp(keyword, "major") == 0) {
			file_hdr->c_dev_maj = atoi(value);	
			did_major = 1;
		} else if (strcmp(keyword, "minor") == 0) {
			file_hdr->c_dev_min = atoi(value);	
			did_minor = 1;
		} else if (strcmp(keyword, "type") == 0) {
			info_filetype = (int)(*value);	
			did_type = 1;
		}
	}

	/*
	* Now add the type bits to the mode field
	*/
	tartype = swheader_getTarTypeFromTypeAttribute(info_filetype);
	if (tartype == LNKTYPE)
		file_hdr->c_is_tar_lnktype = 1;
	else
		file_hdr->c_is_tar_lnktype = 0;
	taru_set_filetype_from_tartype((char)tartype,
			(modet=(mode_t)(file_hdr->c_mode), &modet), "/");
	file_hdr->c_mode = (unsigned long)modet;

	/*
	* Now set the user/group lookup policy based on what was
	* present in the INFO file "file" object.
	*/

	if (did_uname && did_uid) {
		file_hdr->c_cu = TARU_C_BY_UNONE;
	} else if (did_uid) {
		ahsStaticSetTarUsername(file_hdr, "");
		file_hdr->c_cu = TARU_C_BY_UNONE;
	}

	if (did_gname && did_gid) {
		file_hdr->c_cg = TARU_C_BY_UNONE;
	} else if (did_gid) {
		ahsStaticSetTarGroupname(file_hdr, "");
		file_hdr->c_cg = TARU_C_BY_UNONE;
	}

	/*
	* do a sanity check
	*/
	if (
		(!did_gname && !did_gid) ||
		(!did_uname && !did_uid)
	) {
		return 1;
	}

	if (!did_gid) {
		ret = taru_get_gid_by_name(ahsStaticGetTarGroupname(file_hdr), &gid);
		if (ret == 0) {
			file_hdr->c_gid = (unsigned long)gid;
		}
	}

	if (!did_uid) {
		ret = taru_get_uid_by_name(ahsStaticGetTarUsername(file_hdr), &uid);
		if (ret == 0) {
			file_hdr->c_uid = (unsigned long)uid;
		}
	}

	/*
	* FIXME, need to impose required attributes per spec.
	*/

	return 0;
}

char 
swheader_getTarTypeFromTypeAttribute(char ch) {
	switch (ch) {
		case 'f':
			return REGTYPE;
		case 'd':
			return DIRTYPE;
		case 'c':
			return CHRTYPE;
		case 'b':
			return BLKTYPE;
		case 'p':
			return FIFOTYPE;
		case 's':
			return SYMTYPE;
		case 'h':
			return LNKTYPE;
		default:
			fprintf(stderr, "warning:  ISO 15068-2 file type [%c]  not found, returning regular file.\n", ch);
			return REGTYPE;
	}
}

void
swheader_print_header(SWHEADER * swheader)
{
            char * next_attr;
            char * next_line;
            swheader_reset(swheader);
            swheader_set_current_offset_p_value(swheader, 0);

            next_line = swheader_get_next_object(swheader, 
				(int)UCHAR_MAX, (int)UCHAR_MAX);
            while (next_line){
                    swheaderline_write_debug(next_line, STDERR_FILENO);

                    swheader_goto_next_line((void *)swheader, 
				swheader_get_current_offset_p(swheader), 
				SWHEADER_PEEK_NEXT);

                    while((next_attr=swheader_get_next_attribute(swheader)))
                            swheaderline_write_debug(next_attr, STDERR_FILENO);
                    next_line = swheader_get_next_object(swheader, 
					(int)UCHAR_MAX, (int)UCHAR_MAX);
            }
	
}
