#include <stdio.h>
#include <osbind.h>
#include "detar.h"

extern char *tbuf;

static union record tar_rec;
static struct s_q
{
    char name[NAMSIZ];
    char link[NAMSIZ];
    int mode,linkflag;
    long size;
}my_header;

static struct link_q
{
    struct link_q *prev;
    char name[NAMSIZ];
    char link[NAMSIZ];
}*link_list,*new_link,*todo_link;

extern long from_oct();
extern int chec_chksum();
extern int nodev, nopath, tfile, xtract, type, verbos;
extern FILE *ftar;
extern char *to_gem();

static int read_header()
{
    int chk;
    do
    {
        if(tfile)
        {
            fread(tar_rec.charptr,1,RECORDSIZE,ftar);
            if(feof(ftar))return -1;
        }
        else
        {
            tread(tar_rec.charptr,RECORDSIZE);
            if(!tar_rec.charptr[0]) return -1;
        }
        chk=chec_chksum(&tar_rec);
    }while(chk==2);
    return chk;
}

do_detar(test)int (*test)();
{
    int chk;
    long fsiz;
    char *p;
    extern char *index(), *rindex();

    link_list=NULL;
    while((chk=read_header())>=0)
    {
	if((Crawio(255) & 0xff) == 3)
	{
	    fprintf(stderr, "User interrupt, Aborting\n");
	    if(tfile) fclose(ftar);
	    else tclose();
	    Exit(1);
	}

        if(chk==0)
        {
            fprintf(stderr, "Checksum error on %s aborting",tar_rec.header.name);
            Exit(2);
        }
        if(tar_rec.header.name[strlen(tar_rec.header.name)-1]=='/')
        {
            tar_rec.header.name[strlen(tar_rec.header.name)-1]='\0';
            my_header.linkflag=LF_DIR;
        }
        else
            my_header.linkflag=tar_rec.header.linkflag;
        strcpy(my_header.name,to_gem(tar_rec.header.name));
        strcpy(my_header.link,to_gem(tar_rec.header.linkname));
        my_header.size=from_oct(12,tar_rec.header.size);

        if(!(*test)(my_header.name))
	{
	    if(!tfile)
	    {
	        if(tspace(my_header.size))
		    Exit(1);
	    }
	    else
	    {
		for(fsiz = 0L; fsiz < my_header.size; fsiz += 512L)
		{
            	    fread(tar_rec.charptr,1,RECORDSIZE,ftar);
	            if(feof(ftar))return -1;
		}
	    }
	    continue;
	}
        switch(my_header.linkflag)
        {
            case LF_OLDNORMAL:
            case LF_NORMAL:
            case LF_CHR:
            case LF_BLK:
            case LF_FIFO:
            case LF_CONTIG:
            {
                FILE *fout;
                int n;
		long mtime;

                if(xtract)
                {
		    if(nodev)
		    {
	    	        p = index(my_header.name, ':') + 2;
	    	        if(p) sprintf(my_header.name, "%s", p);
		    }
		    if(nopath)
		    {
	    	        p = rindex(my_header.name, '\\') + 1;
	    	        if(p) sprintf(my_header.name, "%s", p);
		    }

                    Makedirs(my_header.name);
                    if((fout=fopen(my_header.name, "wb"))==NULL)
                    {
                        fprintf(stderr,"tar:Can't open %s\n", my_header.name);
                        Exit(3);
                    }
                }
                if(type || verbos)
                {
		    mtime=from_oct(12,tar_rec.header.mtime);
		    if(xtract) printf("x ");
		    n=from_oct(8,tar_rec.header.mode);
		    vtype(n, my_header.size, mtime, my_header.name);
		    if(!xtract)
		    {
	    		if(!tfile)
			{
	        	    if(tspace(my_header.size)) Exit(1);
			}
	    		else
	    		{
			    for(mtime = 0L; mtime < my_header.size; mtime += 512L)
			    {
            	    		fread(tar_rec.charptr,1,RECORDSIZE,ftar);
	            		if(feof(ftar))return -1;
			    }
	    		}
			break;
		    }
                }
                while(my_header.size >0)
                {
                    if(tfile)
                        fread(tar_rec.charptr,1,RECORDSIZE,ftar);
                    else
                        tread(tar_rec.charptr,RECORDSIZE);
                    n=(my_header.size>RECORDSIZE)?RECORDSIZE: (int)my_header.size;
                    if(xtract) fwrite(tar_rec.charptr,1,n,fout);
		    else { for(n = 100; n > 0; n--); }
                    my_header.size = my_header.size - RECORDSIZE;
                
                }
                if(xtract)
		{
		    fclose(fout);
		}
                break;
            }
            case LF_LINK:
            case LF_SYMLINK:
                new_link=(struct link_q *)malloc(sizeof(struct link_q));
                new_link->prev=link_list;
                strcpy(new_link->name,my_header.name);
                strcpy(new_link->link,my_header.link);
                link_list=new_link;
                break;
            case LF_DIR:
                if(xtract && !nopath)
		{ 
		    if(nodev)
		    {
	    	        p = index(my_header.name, ':') + 2;
	    	        if(p) sprintf(my_header.name, "%s", p);
		    }
		    mkdir(my_header.name);
		}
                break;
        }
    }
    do
    {
        todo_link=NULL; 
        while(link_list)
        {
            struct stat stbuf;

            new_link=link_list;
            link_list=new_link->prev;
            if(stat(new_link->link,&stbuf))
            {
                new_link->prev=todo_link;
                todo_link=new_link;
            }
            else
            {
                FILE *fin,*fout;
                int n;
                if(xtract)
                {
                    Makedirs(new_link->name);
                    if((fin=fopen(new_link->link,"rb"))==NULL)
                    {
                        fprintf(stderr, "tar: Cant open %s for copying\n", new_link->link);
                        Exit(3);
                    }
                    if((fout=fopen(new_link->name,"wb"))==NULL)
                    {
                        fprintf(stderr, "tar: Can't open %s to copy to\n", new_link->name);
                        Exit(3);
                    }
                    for(n=RECORDSIZE;n;)
                    {
                        n=fread(tar_rec.charptr,1,RECORDSIZE, fin);
                        fwrite(tar_rec.charptr,1,n,fout);
                    }
                    fclose(fin);
                    fclose(fout);
                    free(new_link);
		}
            }
        }
        link_list=todo_link;
    }while(todo_link);
}
