/* $Id: topsf.c,v 1.13 2000/10/15 13:17:16 jhl Exp jhl $
   topsf.c  --  Open an any format and translate to a PSF with the archive.

   Copyright (C) 1999  Jim Lowe 
   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 "swfork.h"
#include "topsf.h"
#include "cpiohdr.h"
#include "swvarfs.h"
#include "xformat.h"
#include "swutilname.h"
#include "rpmpsf.h"
#include "um_header.h"

static int print_links(TOPSF * topsf);
static void topsf_i_package_close(TOPSF * topsf);
static void topsf_i_bail(TOPSF * topsf);
static TOPSF * topsf_i_package_open(TOPSF * topsf, int oflags);
static int topsf_rpm_find_linkname(TOPSF * topsf, char * baselink, int fd, struct new_cpio_header *file_hdr, int format);
static int topsf_rpm_do_audit_hard_links(TOPSF * topsf, int fd, int oflags, char * decomp);

static
int
find_link(TOPSF * topsf, char * keyname)
{
	int i;
	char * name;
	char * linkname;
	CPLOB * node_names=topsf->hl_node_names_, *linkto_names=topsf->hl_linkto_names_;
	
	if (strstr(keyname, "./") == keyname) keyname+=2;
	i = 0;
	while ((name = cplob_val(node_names, i))) {
		linkname = cplob_val(linkto_names, i);
		/*
		if (strstr(name, "./") == name) name+=2;
		if (strstr(linkname, "./") == linkname) linkname+=2;
		*/
		if (swlib_compare_8859(keyname, name) == 0 || swlib_compare_8859(keyname, linkname) == 0) return 1;
		i++;
	}
	return 0;
}	

void topsf_set_taru(TOPSF * topsf, TARU * taru) { topsf->taruM = taru; }

TOPSF * topsf_open(char * package_name, int oflags)
{
	TOPSF * topsf=(TOPSF*)malloc(sizeof(TOPSF));
	
	oflags |= UINFILE_DETECT_NATIVE;
	oflags |= UINFILE_DETECT_FORCEUNIXFD;

	topsf->swacfl_=swacfl_open();
	topsf->fd_=uinfile_open(package_name, (mode_t)(NULL), &(topsf->format_desc_), oflags); 
	
	if (topsf->fd_ < 0) {
		fprintf(stderr, "%s: error opening package.\n", swlib_utilname_get());
		swacfl_close(topsf->swacfl_);
		swbis_free(topsf);
		return NULL;
	}
	topsf->cwd_prefix_=(char*)(NULL);
	topsf->prefix_=(char*)(NULL);
	topsf->hl_node_names_ = cplob_open(1);
	topsf->hl_linkto_names_ = cplob_open(1);
	topsf->archive_names_ = cplob_open(1);
	cplob_additem(topsf->hl_node_names_, 0, NULL);
	cplob_additem(topsf->hl_linkto_names_, 0, NULL);
	cplob_additem(topsf->archive_names_, 0, NULL);
	topsf->user_addr=NULL;
	topsf->use_recursive_ = 0;
	topsf->reverse_links_ = 0;
	topsf->debug_link_ = 0;
	topsf->single_fileset_ = 0;
	topsf->info_only_ = 0;
	topsf->smart_path_ = 0;
	topsf->form_ = 0;
	topsf->control_directoryM = strob_open(10);
	topsf->taruM = taru_create();
	time(&(topsf->mtimeM));
	return topsf_i_package_open(topsf, oflags);
}

static void 
topsf_i_bail(TOPSF * topsf) 
{
	swacfl_close(topsf->swacfl_);
	uinfile_close(topsf->format_desc_);
	uxfio_close(topsf->fd_);	
	swbis_free(topsf);
}

void 
topsf_close(TOPSF * topsf)
{
	swacfl_close(topsf->swacfl_);
	topsf_i_package_close(topsf);
	uinfile_close(topsf->format_desc_);
	uxfio_close(topsf->fd_);	
	if(topsf->prefix_) swbis_free(topsf->prefix_);
	swbis_free(topsf);
}

static 
TOPSF *
topsf_i_package_open(TOPSF * topsf, int oflags) {
	int rc, isSource;
	STROB * tagval = strob_open(12);
	int tagret = -1;
	int deb_data_fd;
	int ret;

	SWBIS_E_DEBUG("FUNCTION ENTER");
	switch (uinfile_get_type(topsf->format_desc_)) {
		case RPMRHS_FILEFORMAT:
			topsf->rpmfd_=rpmfd_open((FD_t)NULL, topsf->fd_);	
			rc = rpmReadPackageHeader(topsf_rpmFD(topsf), &(topsf->h_), &isSource, NULL, NULL);
			if (rc || !topsf->h_) {
				fprintf(stderr, "lxpsf: error reading package in rpmReadPackageHeader().\n");
				topsf_i_bail(topsf);
				SWBIS_E_DEBUG("ABNORMAL FUNCTION EXIT");
				strob_close(tagval);
				return (TOPSF*)(NULL);
			}

			#ifdef RPMPSF_RPM_HAS_PAYLOADCOMPRESSOR
				tagret = rpmpsf_get_rpmtagvalue(topsf->h_, RPMTAG_PAYLOADCOMPRESSOR, 0, (int*)(NULL), tagval);
			#endif
			if (tagret != 0) {
				strob_strcpy(tagval, "gzip");
			}

			if ((oflags & TOPSF_OPEN_NO_AUDIT) == 0) {
				if (topsf_rpm_do_audit_hard_links(topsf, topsf->fd_, oflags, strob_str(tagval))) {
					SWBIS_E_DEBUG("ABNORMAL FUNCTION EXIT");
					strob_close(tagval);
					return NULL;
				}
			}
			break;
		case DEB_FILEFORMAT:
				/* fprintf(stderr, "lxpsf: deb format detected.\n"); */
				topsf->rpmfd_ = NULL;
				swlib_pipe_pump(STDOUT_FILENO, topsf->fd_);
				ret = uxfio_lseek(topsf->format_desc_->underlying_fdM, TARU_AR_HEADER_SIZE+1, SEEK_CUR);
				SWLIB_ASSERT(ret >= 0);
				deb_data_fd = topsf->format_desc_->underlying_fdM;
				swlib_pipe_pump(-1/*STDOUT_FILENO*/, deb_data_fd);
			break;
				/*
				rc = topsf_deb_read_control_archive(topsf, topsf->fd_);
				if (topsf_deb_do_audit_hard_links(topsf, topsf->fd_, oflags)) {
					SWBIS_E_DEBUG("ABNORMAL FUNCTION EXIT");
					strob_close(tagval);
					return NULL;
				}
				*/
				/*
				 * the package file descriptor is now at the end of the
				 * control.tar.gz file
				 */

			break;
		default:
				fprintf(stderr, "lxpsf: unrecognized package format.\n");
				topsf_i_bail(topsf);
				SWBIS_E_DEBUG("ABNORMAL FUNCTION EXIT");
				strob_close(tagval);
				return (TOPSF*)(NULL);
			break;
	}
	SWBIS_E_DEBUG("FUNCTION EXIT");
	strob_close(tagval);
	return topsf;
}

static void
topsf_i_package_close(TOPSF * topsf) {
	SWBIS_E_DEBUG("FUNCTION ENTER");
	switch (uinfile_get_type(topsf->format_desc_)) {
		case RPMRHS_FILEFORMAT:
			headerFree(topsf->h_);
		break;
		case DEB_FILEFORMAT:
		
		break;
		default:
			fprintf(stderr, "unrecognized format in topsf_close().\n");
		break;
	}
	SWBIS_E_DEBUG("FUNCTION EXIT");
}

o__inline__
int 
topsf_get_fd(TOPSF * topsf)
{
	return topsf->fd_;
}

void 
topsf_set_mtime(TOPSF * topsf, time_t tm)
{
	topsf->mtimeM = tm;
}

o__inline__
void 
topsf_set_fd(TOPSF * topsf, int fd)
{
	topsf->fd_=fd;
}

o__inline__
UINFORMAT * 
topsf_get_format_desc(TOPSF * topsf)
{
	return topsf->format_desc_;
}

o__inline__
Header 
topsf_get_rpmheader(TOPSF * topsf)
{
	return topsf->h_;
}

o__inline__
SWACFL *
topsf_get_archive_filelist(TOPSF * topsf)
{
	return topsf->swacfl_;
}

void 
topsf_add_fl_entry(TOPSF * topsf, char * to_name, char * from_name, int source_code)
{
	SWBIS_E_DEBUG("FUNCTION ENTER");
	/*
	* from_name is the  name in the converted archive.
	* to_name is the name the original rpm archive.
	*/
	/* fprintf(stderr, "to_name=[%s], from_name=[%s]\n", to_name, from_name);  */
	if (topsf->cwd_prefix_) { 
		if (!strstr(from_name, topsf->cwd_prefix_)) {
			SWBIS_E_DEBUG("exception");
		} else {
			/* int i = strlen(topsf->cwd_prefix_); */
			from_name+=strlen(topsf->cwd_prefix_);
			/* if (*from_name == '/') from_name++; */
			from_name--;   /* backup one char to get off the '/' */
			/* Now back up over the name-version-release */

			/* FIXME
			*  the name-version-release is not present in all psf-forms
			*  supported by the lxpsf program
			*/
			/*
			while (*from_name != '/' && i) {
				from_name--; i--; 
				fprintf(stderr, "FROM NAME+ [%s]\n", from_name);
			}
			from_name++; */ /* move forward off the '/'*/
		}
	}
	swacfl_add(topsf->swacfl_, to_name, from_name, source_code);
	SWBIS_E_DEBUG("FUNCTION EXIT");
}

o__inline__
char *
topsf_get_cwd_prefix(TOPSF * topsf)
{
	return topsf->cwd_prefix_;
}

o__inline__
char *
topsf_get_psf_prefix(TOPSF * topsf)
{
	return topsf->prefix_;
}

o__inline__
void
topsf_set_cwd_prefix(TOPSF * topsf, char * p)
{
	topsf->cwd_prefix_=swlib_strdup(p);
}

o__inline__
void
topsf_set_psf_prefix(TOPSF * topsf, char * p)
{
	topsf->prefix_=swlib_strdup(p);
}

static
int
topsf_rpm_do_audit_hard_links(TOPSF * topsf, int fd, int oflags, char * decomp)
{
	char buf[6];
	int buffertype;
	int uxfio_fd, pid;
	int opipe[2];	
	SHCMD *cmd[100];	
	UINFORMAT * uinformat;
	
	SWBIS_E_DEBUG("FUNCTION ENTER");

	buffertype = uinfile_decode_buftype(oflags, UXFIO_BUFTYPE_DYNAMIC_MEM);

	cmd[0]=shcmd_open();
	shcmd_add_arg(cmd[0], decomp);
	shcmd_add_arg(cmd[0], "-d");
	shcmd_set_exec_function(cmd[0], "execvp");
	cmd[1]=NULL;

	uinformat = topsf_get_format_desc(topsf);
	pipe(opipe);
	
	pid = swfork((sigset_t*)(NULL));
	
	if (!pid) {
		close(opipe[0]);
		shcmd_set_srcfd(cmd[0], fd);
		shcmd_set_dstfd(cmd[0], opipe[1]);
		swlib_exec_filter(cmd, 0);
		uxfio_close(fd);
		_exit(0);
	}
	close(opipe[1]);
	SWBIS_E_DEBUG("just before uxfio_opendup");
	uxfio_fd=uxfio_opendup(opipe[0], buffertype);
	SWBIS_E_DEBUG("just after uxfio_opendup");
	SWBIS_E_DEBUG2("uxfio_fd\n%s", uxfio_dump_string(uxfio_fd));
	
	
	/* Peek at at cpio header magic, rpm (depending on the vintage)
	   may use either format */

	if (uxfio_sfread(uxfio_fd, buf, 6) != 6) {
		return -1;
	}

	if (!strncmp(buf, "070701", 6)) {
		uinfile_set_type(uinformat, CPIO_NEWC_FILEFORMAT);
	} else if (!strncmp(buf, "070702", 6)) {
		uinfile_set_type(uinformat, CPIO_CRC_FILEFORMAT);
	} else {
		SWBIS_E_DEBUG("error");
		return -1;
	}

	if (uxfio_lseek(uxfio_fd,(long int)(-6), SEEK_CUR) < 0) {
		SWBIS_E_DEBUG("uxfio_lseek error");
		return -1;
	}
	
	if (topsf_rpm_audit_hard_links(topsf, uxfio_fd)){
		SWBIS_E_FAIL("error in topsf_audit_hard_links, exiting...");
		exit(1);
	}

	if (uxfio_lseek(uxfio_fd, 0L, SEEK_SET) < 0){
		SWBIS_E_FAIL("error from uxfio_lseek");
		return -1;
	}
	SWBIS_E_DEBUG2("closing fd=[%d]", fd);
	SWBIS_E_DEBUG2("fd\n%s", uxfio_dump_string(fd));
	uxfio_close(fd);
	SWBIS_E_DEBUG2("setting topsf fd to [%d]", uxfio_fd);
	topsf_set_fd(topsf, uxfio_fd);
	SWBIS_E_DEBUG2("topsf fd\n%s", uxfio_dump_string(topsf_get_fd(topsf)));
	uinfile_set_type(uinformat, RPMRHS_FILEFORMAT);
	if (topsf->debug_link_) print_links(topsf);
	return 0;	
}

static
void
add_link_pair(TOPSF *topsf, char * base_link, char * link) {

	if (find_link(topsf, link)) return;
	/* fprintf(stderr, "ADD:  Adding [%s] ==  [%s]\n", base_link, link); */
	if (topsf->debug_link_) fprintf(stderr, "ADD:  Adding [%s] ==  [%s]\n", base_link, link);
	cplob_additem(topsf->hl_node_names_, cplob_get_nused(topsf->hl_node_names_)-1, strdup(base_link));
	cplob_additem(topsf->hl_node_names_, cplob_get_nused(topsf->hl_node_names_), NULL);
	cplob_additem(topsf->hl_linkto_names_, cplob_get_nused(topsf->hl_linkto_names_)-1, strdup(link));
	cplob_additem(topsf->hl_linkto_names_, cplob_get_nused(topsf->hl_linkto_names_), NULL);
}


int
topsf_rpm_audit_hard_links(TOPSF * topsf, int fd)
{
	STROB * tmp = strob_open(10);
	struct new_cpio_header *file_hdr=ahsStaticCreateFilehdr();
	int format=uinfile_get_type(topsf->format_desc_);

	SWBIS_E_DEBUG("FUNCTION ENTER");
	while(1) {
		if (taru_read_header(topsf->taruM, file_hdr, fd, format, NULL, 0) < 0){
			fprintf(stderr,"header error %s\n", ahsStaticGetTarFilename(file_hdr));
			return -1;
		}
		/* fprintf(stderr, "FILENAME = [%s]\n", ahsStaticGetTarFilename(file_hdr)); */
		if (!strcmp(ahsStaticGetTarFilename(file_hdr), "TRAILER!!!")) {
			break;
		}
		
		/* fprintf(stderr, "ADDING FILENAME = [%s]\n", ahsStaticGetTarFilename(file_hdr));  */
		cplob_additem(topsf->archive_names_, 
				cplob_get_nused(topsf->archive_names_)-1, 
						swlib_strdup(ahsStaticGetTarFilename(file_hdr)));
		cplob_additem(topsf->archive_names_, cplob_get_nused(topsf->archive_names_), NULL);
		
		/* FIXME check for eoa */
		if ((file_hdr->c_mode & CP_IFMT) == CP_IFREG) {
			if (taru_write_archive_member_data(topsf->taruM, file_hdr,
						-1, fd, (int(*)(int))NULL, format, -1, NULL) < 0){
				fprintf(stderr,"data error %s\n", ahsStaticGetTarFilename(file_hdr));
				return -2;
			}
			taru_tape_skip_padding (fd, file_hdr->c_filesize, format);
		}		

                if (file_hdr->c_nlink > 1 && (((file_hdr->c_mode & CP_IFMT) == CP_IFREG) || /* found link */
                                            ((file_hdr->c_mode & CP_IFMT) == CP_IFBLK) ||
                                            ((file_hdr->c_mode & CP_IFMT) == CP_IFCHR) ||
                                            ((file_hdr->c_mode & CP_IFMT) == CP_IFSOCK))
                 ) {
				
			if (topsf->debug_link_) fprintf(stderr, "Found First : name = %s linkname=[%s]\n", 
				ahsStaticGetTarFilename(file_hdr), ahsStaticGetTarLinkname(file_hdr));
			add_link_pair(topsf, ahsStaticGetTarFilename(file_hdr), ahsStaticGetTarFilename(file_hdr));
			strob_strcpy(tmp, ahsStaticGetTarFilename(file_hdr));
			topsf_rpm_find_linkname(topsf, strob_str(tmp), fd, file_hdr, format);
		} else  if (file_hdr->c_nlink > 1) {
			;
			/* 
			fprintf(stderr,"warning: directory with nlink greater than 1. %s\n", 
					ahsStaticGetTarFilename(file_hdr)); 
			*/
		}
	}
	ahsStaticDeleteFilehdr(file_hdr);
	strob_close(tmp);
	return 0;
}

FD_t
topsf_rpmFD(TOPSF * topsf)
{
	return rpmfd_getfd(topsf->rpmfd_);
}


static int
print_links(TOPSF * topsf)
{
	int i = 0;
	char * name;
	char * linkname;
	CPLOB * node_names=topsf->hl_node_names_, *linkto_names=topsf->hl_linkto_names_;
	
	while ((name = cplob_val(node_names, i))) {
		linkname = cplob_val(linkto_names, i);
		fprintf(stderr, "PRINT: name = [%s], linkname = [%s]\n", name, linkname ? linkname : "<nil>");
		i++;
	}
	return 0;
}	


static
int
topsf_rpm_find_linkname(TOPSF * topsf, char * base_link, int fd, struct new_cpio_header *base_file_hdr, int format)
{
	char * lastmatch=NULL;
	struct new_cpio_header *file_hdr1=ahsStaticCreateFilehdr();
	int oldoffset = uxfio_lseek(fd, 0L, SEEK_CUR);

	SWBIS_E_DEBUG("FUNCTION ENTER");
	while(1) {
		if (taru_read_header(topsf->taruM, file_hdr1, fd, format, NULL, 0) < 0){
			fprintf(stderr,"header error %s\n", ahsStaticGetTarFilename(file_hdr1));
			exit(1);
		}

		if ((file_hdr1->c_mode & CP_IFMT) == CP_IFREG) {
			if (taru_write_archive_member_data(topsf->taruM, file_hdr1,
						-1, fd, (int(*)(int))NULL, format, -1, NULL) < 0){
				fprintf(stderr,"data error %s\n", ahsStaticGetTarFilename(file_hdr1));
				exit(1);
			}
			taru_tape_skip_padding (fd, file_hdr1->c_filesize, format);
		}		
		if (file_hdr1->c_ino == base_file_hdr->c_ino){  /* FIXME need to check the device */
			if (lastmatch) swbis_free(lastmatch);	
			if (topsf->debug_link_)
				fprintf(stderr, "*Found linked files %s %s\n",
					base_link, ahsStaticGetTarFilename(file_hdr1));
			add_link_pair(topsf, base_link, ahsStaticGetTarFilename(file_hdr1));
			lastmatch=swlib_strdup(ahsStaticGetTarFilename(file_hdr1));
		}
		
		if (!strcmp(ahsStaticGetTarFilename(file_hdr1),"TRAILER!!!"))
			break;
	}
	ahsStaticSetTarLinkname(base_file_hdr, lastmatch);
	ahsStaticDeleteFilehdr(file_hdr1);
	SWBIS_E_DEBUG("FUNCTION EXIT");
	if (uxfio_lseek(fd, oldoffset, SEEK_SET) != oldoffset) {
		fprintf(stderr, "error seeking back in topsf_rpm_find_linkname\n");
		exit(2);
	}
	return 0;
}


int
topsf_copypass_swacfl_header_list(TOPSF * topsf, XFORMAT * xxformat, SWVARFS * swvarfs, int ofd)
{
	int done;
	int en_index=0;
	int pheader[2];
	char * p;
	char * savep;
	pid_t pid;
	struct new_cpio_header *file_hdr=ahsStaticCreateFilehdr();
	swacfl_entry * en;
	SWACFL *swacfl=topsf->swacfl_;
	int (*do_write_file)(TOPSF * topsf, int o_fd);

	done = 0;
	while (!done && (en=(swacfl_entry*)cplob_val(swacfl->entry_array_, en_index++))) {
		savep = swlib_strdup(strob_str(en->archiveNameM));
		p = savep;
		if (*p == '/') p++;	
		switch(en->source_code_){
			case SWACFL_SRCCODE_ARCHIVE_STREAM:	
				done = 1;
				break;	
			
			case SWACFL_SRCCODE_RPMHEADER:
			case SWACFL_SRCCODE_PSF:

				SWBIS_E_DEBUG("in SWACFL_SRCCODE_PSF");
				file_hdr->c_magic=CPIO_NEWASCII_MAGIC;	
				file_hdr->c_ino=1;
				file_hdr->c_mode = (0644);
				file_hdr->c_mode |= CP_IFREG;
				file_hdr->c_uid=getuid();
				file_hdr->c_gid=getgid();
				file_hdr->c_nlink=1;
				ahsStaticSetTarLinkname(file_hdr, NULL);
				file_hdr->c_mtime=topsf->mtimeM;
				file_hdr->c_filesize=0;
				file_hdr->c_namesize=strlen(en->from_name_) +1;
				file_hdr->c_chksum=0;
				ahsStaticSetTarFilename(file_hdr, en->from_name_);
				ahsStaticSetTarLinkname(file_hdr, NULL);

				switch(en->source_code_){
					case SWACFL_SRCCODE_RPMHEADER:
						SWBIS_E_DEBUG("in SWACFL_SRCCODE_PSF: SWACFL_SRCCODE_RPMHEADER");
						topsf->user_addr=p;
						file_hdr->c_filesize=rpmpsf_get_rpmtag_length(topsf, p) + 1;
						do_write_file=rpmpsf_write_out_tag;
						SWBIS_E_DEBUG("leaving SWACFL_SRCCODE_PSF: SWACFL_SRCCODE_RPMHEADER");
						break;
					case SWACFL_SRCCODE_PSF:
						SWBIS_E_DEBUG("in SWACFL_SRCCODE_PSF: SWACFL_SRCCODE_PSF");
						file_hdr->c_filesize=rpmpsf_get_psf_size(topsf);
						do_write_file=rpmpsf_write_beautify_psf;
						SWBIS_E_DEBUG("leaving SWACFL_SRCCODE_PSF: SWACFL_SRCCODE_PSF");
						break;	
					default:
						SWBIS_E_FAIL("fatal");
						exit(1);
				}
				pipe(pheader);
				pid = swfork((sigset_t*)(NULL));
				if (pid < 0){
					SWBIS_E_FAIL("fatal, fork error");
					_exit(1);
				} else if (pid == 0) {
					close(pheader[0]);
					(*do_write_file)(topsf, pheader[1]);
					if (en->source_code_ == SWACFL_SRCCODE_RPMHEADER) {
						write(pheader[1], "\n", 1);
					}
					_exit(0);
				}
				close(pheader[1]);
				
				xformat_write_by_fd(xxformat, pheader[0], file_hdr);
				SWBIS_E_DEBUG3("OK %s %s", p, en->from_name_);
				SWBIS_E_DEBUG("leaving SWACFL_SRCCODE_PSF");
				break;
			
			case SWACFL_SRCCODE_FILESYSTEM:
				SWBIS_E_FAIL("bad case error");
				break;
		}
	}
	ahsStaticDeleteFilehdr(file_hdr);
	SWBIS_E_DEBUG("FUNCTION EXIT");
	return 0;
}


int
topsf_copypass_swacfl_archive_list(TOPSF * topsf, XFORMAT * xxformat, SWVARFS * swvarfs, int ofd)
{
	int u_fd;
	int pheader[2];
	char * p;
	char * savep = NULL;
	pid_t pid;
	struct new_cpio_header *file_hdr=ahsStaticCreateFilehdr();
	swacfl_entry * en;
	SWACFL *swacfl=topsf->swacfl_;
	struct stat st;
	int (*do_write_file)(TOPSF * topsf, int o_fd);
	CPLOB * archive_names = topsf->archive_names_;
	int archive_name_index = 0;
	char * archive_name;

	while ((archive_name = cplob_val(archive_names, archive_name_index++))) {
		en = swacfl_find_entry(swacfl, archive_name);
		if (!en) {
			fprintf(stderr, "Internal fatal error, swacfl entry not found for [%s]\n", archive_name);
			exit(1);
		}
		if (savep) free(savep);
		savep = swlib_strdup(strob_str(en->archiveNameM));
		p = savep;
		swlib_process_hex_escapes(p);
		if (*p == '/') p++;
		switch(en->source_code_){
			case SWACFL_SRCCODE_ARCHIVE_STREAM:	
				SWBIS_E_DEBUG("in SWACFL_SRCCODE_ARCHIVE_STREAM");
				SWBIS_E_DEBUG("SWACFL_SRCCODE_ARCHIVE_STREAM #1a");
				u_fd=swvarfs_u_open(swvarfs, p);
				SWBIS_E_DEBUG("SWACFL_SRCCODE_ARCHIVE_STREAM #1b");
				if (u_fd < 0) {	
					SWBIS_E_DEBUG("SWACFL_SRCCODE_ARCHIVE_STREAM #1c");
					fprintf(stderr,"swvarfs_u_open error: file %s not found\n", p);
					break;
				}
				SWBIS_E_DEBUG("SWACFL_SRCCODE_ARCHIVE_STREAM #1");
				swvarfs_u_fstat(swvarfs, u_fd, &st);	
				SWBIS_E_DEBUG("SWACFL_SRCCODE_ARCHIVE_STREAM #2");
				taru_statbuf2filehdr(file_hdr, &st,
						(char*)NULL, p/*en->from_name_*/,
						swvarfs_u_get_linkname(swvarfs, u_fd));
				SWBIS_E_DEBUG("SWACFL_SRCCODE_ARCHIVE_STREAM #3");
				file_hdr->c_uid=getuid();
				file_hdr->c_gid=getgid();
				xformat_write_by_fd(xxformat, u_fd, file_hdr);
				SWBIS_E_DEBUG3("OK %s %s", p, en->from_name_);
				ahsStaticSetTarFilename(file_hdr, NULL);
				ahsStaticSetTarLinkname(file_hdr, NULL);
				swvarfs_u_close(swvarfs, u_fd);
				SWBIS_E_DEBUG("leaving SWACFL_SRCCODE_ARCHIVE_STREAM");
				break;

			case SWACFL_SRCCODE_RPMHEADER:
			case SWACFL_SRCCODE_PSF:

				SWBIS_E_DEBUG("in SWACFL_SRCCODE_PSF");
				file_hdr->c_magic=CPIO_NEWASCII_MAGIC;	
				file_hdr->c_ino=1;
				file_hdr->c_mode = (0644);
				file_hdr->c_mode |= CP_IFREG;
				file_hdr->c_uid=getuid();
				file_hdr->c_gid=getgid();
				file_hdr->c_nlink=1;
				ahsStaticSetTarLinkname(file_hdr, NULL);
				file_hdr->c_mtime=topsf->mtimeM;
				file_hdr->c_filesize=0;
				file_hdr->c_namesize=strlen(en->from_name_) +1;
				file_hdr->c_chksum=0;
				ahsStaticSetTarFilename(file_hdr, en->from_name_);
				ahsStaticSetTarLinkname(file_hdr, NULL);

				switch(en->source_code_){
					case SWACFL_SRCCODE_RPMHEADER:
						SWBIS_E_DEBUG("in SWACFL_SRCCODE_PSF: SWACFL_SRCCODE_RPMHEADER");
						topsf->user_addr=p;
						file_hdr->c_filesize = rpmpsf_get_rpmtag_length(topsf, p);
						do_write_file = rpmpsf_write_out_tag;
						SWBIS_E_DEBUG("leaving SWACFL_SRCCODE_PSF: SWACFL_SRCCODE_RPMHEADER");
						break;
					case SWACFL_SRCCODE_PSF:
						SWBIS_E_DEBUG("in SWACFL_SRCCODE_PSF: SWACFL_SRCCODE_PSF");
						file_hdr->c_filesize=rpmpsf_get_psf_size(topsf);
						do_write_file=rpmpsf_write_beautify_psf;
						SWBIS_E_DEBUG("leaving SWACFL_SRCCODE_PSF: SWACFL_SRCCODE_PSF");
						break;	
					default:
						SWBIS_E_FAIL("fatal");
						exit(1);
				}
				pipe(pheader);
				pid = swfork((sigset_t*)(NULL));
				if (pid < 0){
					SWBIS_E_FAIL("fatal, fork error");
					_exit(1);
				} else if (pid == 0) {
					close(pheader[0]);
					(*do_write_file)(topsf, pheader[1]);
					_exit(0);
				}
				close(pheader[1]);
				
				xformat_write_by_fd(xxformat, pheader[0], file_hdr);
				SWBIS_E_DEBUG3("OK %s %s", p, en->from_name_);
				SWBIS_E_DEBUG("leaving SWACFL_SRCCODE_PSF");
				break;
			
			case SWACFL_SRCCODE_FILESYSTEM:
				SWBIS_E_FAIL("bad case error");
				break;
		}
	}
	if (savep) free(savep);
	ahsStaticDeleteFilehdr(file_hdr);
	SWBIS_E_DEBUG("FUNCTION EXIT");
	return 0;
}

int
topsf_copypass_swacfl_list(TOPSF * topsf, int ofd)
{
	int ret;
	SWVARFS * swvarfs;
	XFORMAT * xxformat;
	xxformat = xformat_open(-1, ofd, (int)(arf_newascii));
	swvarfs=swvarfs_opendup(topsf->fd_, 
		UINFILE_DETECT_FORCEUXFIOFD | UINFILE_DETECT_NATIVE | UINFILE_UXFIO_BUFTYPE_DYNAMIC_MEM, (mode_t)(NULL));
	if (!swvarfs) {
		return -1;
	}
	ret = topsf_copypass_swacfl_header_list(topsf, xxformat, swvarfs, ofd);
	if (ret != 0) {
		fprintf(stderr, "topsf_copypass_swacfl_list: error writing header files\n");
		return ret;
	}
	ret = topsf_copypass_swacfl_archive_list(topsf, xxformat, swvarfs, ofd);
	
	swvarfs_close(swvarfs);
 	xformat_write_trailer(xxformat); 
	xformat_close(xxformat);
	return ret;
}

int
topsf_get_fd_fd(TOPSF * topsf) {
	int ret;
	SWBIS_E_DEBUG("FUNCTION ENTER");
	switch (uinfile_get_type(topsf->format_desc_)) {
		case RPMRHS_FILEFORMAT:
			ret= rpmfd_get_fd_fd(topsf->rpmfd_);
			SWBIS_E_DEBUG("FUNCTION EXIT");
			return ret;
		default:
			SWBIS_E_DEBUG("FUNCTION EXIT");
			return topsf->fd_;
			break;
	}
}

char *
topsf_make_package_prefix(TOPSF * topsf, char * cwdir)
{
	char * ret;
	
	SWBIS_E_DEBUG("FUNCTION ENTER");
	switch (uinfile_get_type(topsf->format_desc_)) {
		case RPMRHS_FILEFORMAT:
			ret = rpmpsf_make_package_prefix(topsf, cwdir);
			SWBIS_E_DEBUG("FUNCTION EXIT");
			return ret;
			break;
		case DEB_FILEFORMAT:
			ret = strdup("");
			return ret;
			break;
		default:
			fprintf(stderr, "unrecognized package type.\n");
			break;
	}
	SWBIS_E_DEBUG("FUNCTION EXIT");
	return (char*)(NULL);
}

int
topsf_write_psf(TOPSF * topsf, int fd_out, int do_indent)
{
	int ret;

	SWBIS_E_DEBUG("FUNCTION ENTER");
	switch (uinfile_get_type(topsf->format_desc_)) {
		case RPMRHS_FILEFORMAT:
			if(do_indent) {
				ret = rpmpsf_write_beautify_psf(topsf, fd_out);
				SWBIS_E_DEBUG("FUNCTION EXIT");
				return ret;
			} else {
				ret = rpmpsf_write_psf(topsf, fd_out);
				SWBIS_E_DEBUG("FUNCTION EXIT");
				return ret;
			}
			break;
		case DEB_FILEFORMAT:
			break;
		default:
			fprintf(stderr, "unrecognized package type.\n");
			break;
	}
	SWBIS_E_DEBUG("FUNCTION EXIT");
	return -1;
}

int
topsf_write_info(TOPSF * topsf, int fd_out, int do_indent)
{
	int ret;

	SWBIS_E_DEBUG("FUNCTION ENTER");
	switch (uinfile_get_type(topsf->format_desc_)) {
		case RPMRHS_FILEFORMAT:
			if(do_indent) {
				ret = rpmpsf_write_beautify_info(topsf, fd_out);
				SWBIS_E_DEBUG("FUNCTION EXIT");
				return ret;
			} else {
				ret = rpmpsf_write_info(topsf, fd_out);
				SWBIS_E_DEBUG("FUNCTION EXIT");
				return ret;
			}
			break;
		default:
			fprintf(stderr, "unrecognized package type.\n");
			break;
	}
	SWBIS_E_DEBUG("FUNCTION EXIT");
	return -1;
}
