#include "tarutil.h"
#include "defines.h"
#include <stdlib.h>
#include <stdio.h>
#include <zlib.h>
#include <math.h>
#include <tar.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>

typedef struct stTarType {
	char name[100];
	char mode[8];
	char uid[8];
	char gid[8];
	char size[12];
	char mtime[12];
	char chksum[8];
	unsigned char typeflag;
	char linkname[100];
	char magic[6];
	char version[2];
	char uname[32];
	char gname[32];
	char devmajor[8];
	char devminor[8];
	char prefix[155];
} stTarUtil;

long decToOct(char *octValue)
{
	int i;
	long retValue=0;
	char tempChar[2];

	tempChar[1]='\0';
	for (i=strlen(octValue)-1;i>=0;i--) {
		tempChar[0]=octValue[i];
		retValue+=(atoi(tempChar))*pow(8,strlen(octValue)-1-i);
	}
	return ((long)retValue);
}

TarFileList *getFileList(char *filename)
{
	gzFile gfd;
	int numread;
	char hdrbuf[512];
	long filesize;
	stTarUtil *header;
	TarFileList *first,*current,*tempname;
	char tsize[13];
	
	first=current=NULL;
	gfd=gzopen(filename,"rb");
	if (gfd==NULL) return NULL;
	while ((numread=gzread(gfd,hdrbuf,sizeof(hdrbuf)))>0) {
		header=(stTarUtil *)&hdrbuf;
		memset(tsize,'\0',sizeof(tsize));
		strncpy(tsize,header->size,11);
		filesize=decToOct(tsize);
		gzseek(gfd,filesize,SEEK_CUR);
		if (filesize>0)	gzseek(gfd,512 - (filesize % 512),SEEK_CUR);
		if (header->name[0]=='\0') {
			break;
		} else {
			tempname=(TarFileList *)malloc(sizeof(TarFileList));
			if (tempname==NULL) {
				printf("Error allocating memory\n");
				exit (-1);
			}
			strncpy(tempname->filename,header->name,100);
			tempname->next=NULL;
			if (first==NULL) first=tempname;
			else current->next=tempname;
			current=tempname;
		}
	}
	gzclose(gfd);
	return(first);
}
/*********************************************************************
** checkDirectory()                                                 **
**------------------------------------------------------------------**
** This function handles checking the directory portion of a        **
** filename to see if the directory exists or not.                  **
**------------------------------------------------------------------**
** Parameters:                                                      **
**   The full filename of the file to check                         **
**------------------------------------------------------------------**
** Returns:                                                         **
**   0 on success                                                   **
**  -1 on error                                                     **
*********************************************************************/
int checkDirectory(char *fullName)
{
	char pathName[PATH_MAX];
	char *lastSlash;
	int error;
	DIR *dir;
	
	strncpy(pathName,fullName,PATH_MAX);
	lastSlash=strrchr(pathName,'/');
	if (lastSlash!=NULL) *lastSlash='\0';
	dir=opendir(pathName);
	if (dir==NULL) return -1;
	closedir(dir);

	return 0;
}

/*********************************************************************
** createDirectory()                                                **
**------------------------------------------------------------------**
** This function handles creating a directory, by checking up the   **
** list of directories and trying to create each one that doesn't   **
** exist.                                                           **
**------------------------------------------------------------------**
** Parameters:                                                      **
**   The full path of the directory to be created                   **
**------------------------------------------------------------------**
** Returns:                                                         **
**   0 on success                                                   **
**  -1 on error                                                     **
*********************************************************************/
int createDirectory(char *fullPath)
{
	int error;
	char pathName[PATH_MAX];
	char currPath[PATH_MAX];
	int count;
	
	/* First we'll just try creating the full directory */
	error=mkdir(fullPath,0777);
	/* If it works then we'll just return success */
	if (error==0) return (0);
	return -1;
/*	strncpy(pathName,fullPath,PATH_MAX);
	while ((pathName[count]!='\0')&&(count<PATH_MAX)) {
		if (pathName[count]=='/') {
			strncpy(currPath,pathName,count);
			printf("%s\n",currPath);
		}
		count++;
	}*/
	return 0;
}

int untar(char *filename,char *destdir)
{
	gzFile gfd;
	int numread;
	char hdrbuf[512];
	long filesize;
	stTarUtil *header;
	char tsize[13];
	char fullName[PATH_MAX];
	char pathName[PATH_MAX];
	char *pathPtr;
	char *buffer=NULL;
	FILE *fout;
	int error;
	
	gfd=gzopen(filename,"rb");
	if (gfd==NULL) return;
	while ((numread=gzread(gfd,hdrbuf,sizeof(hdrbuf)))!=0) {
		header=(stTarUtil *)&hdrbuf;
		memset(tsize,'\0',sizeof(tsize));
		strncpy(tsize,header->size,11);
		filesize=decToOct(tsize);
		if (header->name[0]=='\0') break;
		else {
			if (header->typeflag==DIRTYPE) {
				snprintf(fullName,PATH_MAX,"%s%s",destdir,header->name);
				error=checkDirectory(fullName);
				if (error==-1) {
					error=createDirectory(fullName);
					if (error==-1) {
						snprintf(tarError,1024,"Unable to create directory\n%s",fullName);
						gzclose(gfd);
						return (-1);
					}
				}
			} else {
				if (buffer) free(buffer);
				buffer=(char *)malloc(filesize);
				if (buffer!=NULL) {
					snprintf(fullName,PATH_MAX,"%s%s",destdir,header->name);
					error=checkDirectory(fullName);
					if (error) {
						strncpy(pathName,fullName,PATH_MAX);
						pathPtr=strrchr(pathName,'/');
						if (pathPtr!=NULL) {
							*pathPtr='\0';
						}
						error=createDirectory(pathName);
						if (error) {
							snprintf(tarError,1024,"Unable to create directory\n%s",pathName);
							gzclose(gfd);
							return -1;
						}
					}
					fout=fopen(fullName,"w");
					if (fout==NULL) {
						snprintf(tarError,1024,"Unable to open output file\n%s",fullName);
						gzclose(gfd);
						return -1;
					}
					gzread(gfd,buffer,filesize);
					fwrite(buffer,filesize,1,fout);
					fclose(fout);
				}
			}
			if (filesize>0)	gzseek(gfd,512-filesize%512,SEEK_CUR);
		}
	}
	if (buffer) free(buffer);
	gzclose(gfd);
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1