#include <sys/stat.h>
#include <stdio.h>
#include "../machdr/machdr.h"
#include "fileglob.h"
#ifdef AUFS_SUPPORT
#include <netat/appletalk.h>
#include <netat/macfile.h>
#include <ctype.h>
#endif /* AUFS_SUPPORT */

char *malloc();
char *realloc();

#ifdef AUFS_SUPPORT
void aufs_namings();
void wr_aufs_info();
#endif /* AUFS_SUPPORT */

#ifndef BSD
/* all those stupid differences! */
#define bcopy(src,dest,length)	memcpy((dest),(src),(length))
#define bzero(block,length)	memset((block),0,(length))
#endif /* BSD */

#define INFO_FORK	1
#define RSRC_FORK	2
#define DATA_FORK	3

#ifdef BSD
char *sprintf();
#endif /* BSD */

char f_info[I_NAMELEN];
char f_data[I_NAMELEN];
char f_rsrc[I_NAMELEN];
char f_bin[I_NAMELEN];
#ifdef AUFS_SUPPORT
static char hex[] = "0123456789abcdef";
static char infodir[] = ".finderinfo";
static char rsrcdir[] = ".resource";
#define INFOSZ	sizeof(infodir)
#define RSCSSZ	sizeof(rsrcdir)
char f_info_aufs[I_NAMELEN+INFOSZ];
char f_rsrc_aufs[I_NAMELEN+RSCSSZ];
#endif /* AUFS_SUPPORT */

int bytes_read, bytes_written;
int mode;
char *out_buffer, *out_ptr;

char *buffer = NULL;
char *rbuffer = NULL, *dbuffer = NULL;
char *ptr;
unsigned long rsz, dsz, totsize, maxsize;

void define_name(text)
char *text;
{
    (void)sprintf(f_info, "%s.info", text);
    (void)sprintf(f_rsrc, "%s.rsrc", text);
    (void)sprintf(f_data, "%s.data", text);
    (void)sprintf(f_bin, "%s.bin", text);
#ifdef AUFS_SUPPORT
/* Do not do namestuffing here.  We want to base again on the information in
   the info header, so this is delayed
*/
#endif /* AUFS_SUPPORT */
}

void start_info(info, rsize, dsize)
char *info;
unsigned long rsize, dsize;
{
    int rs, ds;

    rsz = rsize;
    dsz = dsize;
    rs = (((rsz + 127) >> 7) << 7);
    ds = (((dsz + 127) >> 7) << 7);
    totsize = rs + ds + 128;
    if(buffer == NULL) {
	buffer = (char *)malloc((unsigned)totsize);
    } else if(maxsize < totsize) {
	buffer = (char *)realloc(buffer, (unsigned)totsize);
	maxsize = totsize;
    }
    if(buffer == NULL) {
	fprintf(stderr, "Insufficient memory, aborting\n");
	exit(1);
    }
    dbuffer = buffer + 128;
    rbuffer = dbuffer + ds;
    (void)bzero(buffer, totsize);
    ptr = buffer;
    (void)bcopy(info, ptr, 128);
#ifdef AUFS_SUPPORT
/* Now we do filenaming etc. */
    if(mode == AUFS) {
	aufs_namings();
    }
#endif /* AUFS_SUPPORT */
}

void start_rsrc()
{
    out_buffer = out_ptr = rbuffer;
}

void start_data()
{
    out_buffer = out_ptr = dbuffer;
}

void end_file()
{
    FILE *fp;
    int i, c;

    buffer[I_FLAGOFF] &= (~INITED_MASK);
    switch(mode) {
    case FULL:
    case FORK:
	fp = fopen(f_info, "w");
	if(fp == NULL) {
	    perror(f_info);
	    exit(1);
	}
	(void) fwrite(buffer, 1, 128, fp);
	(void) fclose(fp);
	if(rsz != 0 || mode == FULL) {
	    fp = fopen(f_rsrc, "w");
	    if(fp == NULL) {
		perror(f_rsrc);
		exit(1);
	    }
	    (void) fwrite(rbuffer, 1, (int)rsz, fp);
	    (void) fclose(fp);
	}
	if(dsz != 0 || mode == FULL) {
	    fp = fopen(f_data, "w");
	    if(fp == NULL) {
		perror(f_data);
		exit(1);
	    }
	    (void) fwrite(dbuffer, 1, (int)dsz, fp);
	    (void) fclose(fp);
	}
	break;
    case RSRC:
	fp = fopen(f_rsrc, "w");
	if(fp == NULL) {
	    perror(f_rsrc);
	    exit(1);
	}
	(void) fwrite(rbuffer, 1, (int)rsz, fp);
	(void) fclose(fp);
	break;
    case DATA:
	fp = fopen(f_data, "w");
	if(fp == NULL) {
	    perror(f_data);
	    exit(1);
	}
	(void) fwrite(dbuffer, 1, (int)dsz, fp);
	(void) fclose(fp);
	break;
    case TEXT:
	fp = fopen(f_data, "w");
	if(fp == NULL) {
	    perror(f_data);
	    exit(1);
	}
	for(i = 0; i < dsz; i++) {
	    c = dbuffer[i];
	    if(c == '\012' || c == '\015') {
		dbuffer[i] = '\027' -c;
	    }
	}
	(void) fwrite(dbuffer, 1, (int)dsz, fp);
	(void) fclose(fp);
	break;
    case MACB:
	fp = fopen(f_bin, "w");
	if(fp == NULL) {
	    perror(f_bin);
	    exit(1);
	}
	if(buffer[I_FLAGOFF + 1] & PROTCT_MASK) {
	    buffer[I_LOCKOFF] = 1;
	}
	buffer[I_FLAGOFF + 1] = 0;
	buffer[I_LOCKOFF + 1] = 0;
	(void)fwrite(buffer, 1, (int)totsize, fp);
	(void)fclose(fp);
	break;
#ifdef AUFS_SUPPORT
    case AUFS:
	fp = fopen(f_info_aufs, "w");
	if(fp == NULL) {
	    perror(f_info_aufs);
	    exit(1);
	}
	wr_aufs_info(fp);
	(void) fclose(fp);
	if(rsz != 0 || mode == FULL) {
	    fp = fopen(f_rsrc_aufs, "w");
	    if(fp == NULL) {
		perror(f_rsrc_aufs);
		exit(1);
	    }
	    (void) fwrite(rbuffer, 1, (int)rsz, fp);
	    (void) fclose(fp);
	}
	if(dsz != 0 || mode == FULL) {
	    fp = fopen(f_data, "w");
	    if(fp == NULL) {
		perror(f_data);
		exit(1);
	    }
	    (void) fwrite(dbuffer, 1, (int)dsz, fp);
	    (void) fclose(fp);
	}
	break;
#endif /* AUFS_SUPPORT */
    }
}

void do_mkdir(name)
char *name;
{
struct stat sbuf;
#ifdef NOMKDIR
char command[21]; /* Systems without mkdir system call but more than 14
		     char file names?  Ridiculous! */
int sysreturn;
#endif /* MKDIR */

    if (stat(name, &sbuf) == -1) {	/* directory doesn't exist */
#ifndef NOMKDIR~
	if (mkdir(name, 0777) == -1) {
	    fprintf(stderr, "Can't create subdirectory %s\n", name);
	    exit(1);
	}
#else /* NOMKDIR */
	sprintf(command, "mkdir %s", name);
	if((sysreturn = system(command)) != 0) {
	    fprintf(stderr, "Can't create subdirectory %s\n", name);
	    exit(sysreturn);
	}
#endif /* NOMKDIR */
    } else {		/* something exists with this name */
	if ((sbuf.st_mode & S_IFMT) != S_IFDIR) {
	    fprintf(stderr, "Directory name %s already in use\n",name);
	    exit(1);
	}
    }
#ifdef AUFS_SUPPORT
    if(mode == AUFS) {
	/* The following test is needed to avoid recursion.  And I do it
	   this way because I want all AUFS specific stuff overhere!
	*/
	if(strcmp(name, rsrcdir) && strcmp(name, infodir)) {
	    chdir(name);
	    do_mkdir(rsrcdir);
	    do_mkdir(infodir);
	    chdir("..");
	}
    }
#endif /* AUFS_SUPPORT */
}

#ifdef AUFS_SUPPORT
void check_aufs()
{
    /* check for .resource/ and .finderinfo/ */
    struct stat stbuf;
    int error = 0;

    if (stat(rsrcdir,&stbuf) < 0)
	error ++;
    else
	if ((stbuf.st_mode & S_IFMT)
	      != S_IFDIR)
		  error ++;
    if (stat(infodir,&stbuf) < 0)
	error ++;
    else
	if ((stbuf.st_mode & S_IFMT)
	      != S_IFDIR)
		  error++;
    if (error) {
	fprintf(stderr,
	    "Not in an Aufs folder.\n");
	exit(1);
    }
}

void aufs_namings()
{
    int ch;
    char *mp, aufs_name[256], *up;

    mp = buffer + 2;
    up = &(aufs_name[0]);
    while (ch = *mp++) {
	if (isascii(ch) && ! iscntrl(ch) && isprint(ch) && ch != '/') {
	    *up++ = ch;
	} else {
	    *up++ = ':';
	    *up++ = hex[(ch >> 4) & 0xf];
	    *up++ = hex[ch & 0xf];
	}
    }
    *up = 0;
    sprintf(f_info_aufs, "%s/%s", infodir, aufs_name);
    sprintf(f_rsrc_aufs, "%s/%s", rsrcdir, aufs_name);
    sprintf(f_data, "%s", aufs_name);
}

void wr_aufs_info(fp)
FILE *fp;
{
    FileInfo theinfo;
    int n;

    bzero((char *) &theinfo,sizeof theinfo);
    theinfo.fi_magic1 = FI_MAGIC1;
    theinfo.fi_version = FI_VERSION;
    theinfo.fi_magic = FI_MAGIC;
    theinfo.fi_bitmap = FI_BM_MACINTOSHFILENAME;

    bcopy(buffer + I_TYPEOFF, theinfo.fi_fndr, 4);
    bcopy(buffer + I_AUTHOFF, theinfo.fi_fndr + 4, 4);
    bcopy(buffer + I_FLAGOFF, theinfo.fi_fndr + 8, 2);
    if ((n = buffer[I_NAMEOFF] & 0x77) > 33) {
	n = 33;
    }
    strncpy(theinfo.fi_macfilename, buffer + I_NAMEOFF + 1,n);
    /* theinfo.fi_macfilename[n] = '\0'; */
    strcpy(theinfo.fi_comnt, "Converted by Unix utility to Aufs format");
    theinfo.fi_comln = strlen(theinfo.fi_comnt);
    fwrite((char *) &theinfo, 1, sizeof theinfo, fp);
}
#endif /* AUFS_SUPPORT */

