#include <conf.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#ifdef	HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include <dirent.h>
#include <fcntl.h>
#ifdef	HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef	HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#include <signal.h>
#include <utime.h>
#include <unistd.h>
#include <utils.h>
#include <fileutil.h>
#include "backup.h"

static Int32
get_int(AarParams * params, Int32 * rptr)
{
  Int32		i, s;
  UChar		c, n;
  Int32		r;

  n = 0;
  r = 0;
  s = 1;

  forever{
    i = params->inputfunc(&c, 1, params);
    if(i == 0)
	return(-1);

    if(c == ';')
	break;

    if(c == '-'){
	if(n || s == -1)
	  return(0);
	s = -1;
    }
    else if(isspace(c)){
	continue;
    }
    else if(c <= '9' && c >= '0'){
	r = (r << 3) + (r << 1) + (c - '0');
	n = 1;
    }
    else
	return(0);
  }

  if(!n)
    return(0);

  *rptr = r * s;

  return(1);
}
    
static Int32
get_uns(AarParams * params, Uns32 * rptr)
{
  Int32		i;
  UChar		c, n;
  Uns32		r;

  n = 0;
  r = 0;

  forever{
    i = params->inputfunc(&c, 1, params);
    if(i == 0)
	return(-1);

    if(c == ';')
	break;

    if(isspace(c)){
	continue;
    }
    else if(c <= '9' && c >= '0'){
	r = (r << 3) + (r << 1) + (c - '0');
	n = 1;
    }
    else
	return(0);
  }

  if(!n)
    return(0);

  *rptr = r;

  return(1);
}

static Int32
get_time_t(AarParams * params, time_t * rptr)
{
  Int32		i;
  UChar		c, n;
  time_t	r;

  n = 0;
  r = (time_t) 0;

  forever{
    i = params->inputfunc(&c, 1, params);
    if(i == 0)
	return(-1);

    if(c == ';')
	break;

    if(isspace(c)){
	continue;
    }
    else if(c <= '9' && c >= '0'){
	r = (r << 3) + (r << 1) + (c - '0');
	n = 1;
    }
    else
	return(0);
  }

  if(!n)
    return(0);

  *rptr = r;

  return(1);
}
    
static Int32
get_size_t(AarParams * params, size_t * rptr)
{
  Int32		i;
  UChar		c, n;
  size_t	r;

  n = 0;
  r = (size_t) 0;

  forever{
    i = params->inputfunc(&c, 1, params);
    if(i == 0)
	return(-1);

    if(c == ';')
	break;

    if(isspace(c)){
	continue;
    }
    else if(c <= '9' && c >= '0'){
	r = (r << 3) + (r << 1) + (c - '0');
	n = 1;
    }
    else
	return(0);
  }

  if(!n)
    return(0);

  *rptr = r;

  return(1);
}
    
static Int32
name_in_list(UChar * name, UChar ** list, UChar subdir, UChar * found)
{
  Int32		len;

  if(!list)
    return(1);

  if(!subdir)
    for(; *list; list++, found++)
      if(!strcmp(*list, name)){
	*found = 1;
	return(1);
      }

  if(subdir)
    for(; *list; list++, found++){
      len = strlen(*list);
      if(!strcmp(*list, name) ||
		(!strncmp(*list, name, len) && (name[len] == FN_DIRSEPCHR
				|| name[len - 1] == FN_DIRSEPCHR))){
	*found = 1;
	return(1);
      }
    }

  return(0);
}

static Int32
formaterr(Int32 * type, AarParams * params, UChar started)
{
  Int32	i;
  Int32	li;

  if(!(!started && params->skip_garbage))
    fprintf(params->errfp,
	"Error: format error in input, trying to skip to the next file ...\n");

  forever{
    if(params->pre_verbosefunc)
	(*params->pre_verbosefunc)(NULL, params);

    i = get_int(params, &li);

    if(i < 0)
	return(-1);	/* -1 */

    if(i == 1){
	*type = (Int32) li;
	return(1);
    }
  }
}

#define	read_int(val, typ)	{ rvr = get_int(params, &li); \
				  if(rvr < 1){ \
				    i = formaterr(&type, params, started); \
				    have_an_error = 1; \
				    goto tryagain; \
				  } \
				  val = (typ) li; }
#define	read_uns(val, typ)	{ rvr = get_uns(params, &lu); \
				  if(rvr < 1){ \
				    i = formaterr(&type, params, started); \
				    have_an_error = 1; \
				    goto tryagain; \
				  } \
				  val = (typ) lu; }
#define	read_time_t(val, typ)	{ rvr = get_time_t(params, &ltt); \
				  if(rvr < 1){ \
				    i = formaterr(&type, params, started); \
				    have_an_error = 1; \
				    goto tryagain; \
				  } \
				  val = (typ) ltt; }
#define	read_size_t(val, typ)	{ rvr = get_size_t(params, &stt); \
				  if(rvr < 1){ \
				    i = formaterr(&type, params, started); \
				    have_an_error = 1; \
				    goto tryagain; \
				  } \
				  val = (typ) stt; }
#define	POSZ(x)			{ if(x < 0) x = 0; }
#define	DP			"--> "	/* the DIFFERENCES_PREFIX */

static UChar
invalid_time_or_uid(time_t mtime, int uid, AarParams * params)
{
  return((params->uid && params->uid != uid)
		|| (params->time_older && params->time_older <= mtime)
		|| (params->time_newer && params->time_newer > mtime));
}

static UChar
not_allowed(UChar * name, int uid)
{
  UChar		lname[MAXPATHLEN + 2], *cptr;
  struct stat	statb;

  if(!uid)
    return(0);
  if(!name[0])
    return(1);

  strcpy(lname, name);
  cleanpath(lname);

  forever{
    if(!stat(lname, &statb))	/* fs-entry exists, can read it */
	return(statb.st_uid != uid ? 1 : 0);

    cptr = FN_LASTDIRDELIM(lname);	/* get last / */
    if(cptr)
	*cptr = '\0';
    if(!lname[0])
	return(1);		/* was absolute path */

    if(!cptr){			/* name remaining in current dir */
	if(stat(".", &statb))
	  return(1);

	return(statb.st_uid != uid ? 1 : 0);
    }
  }

  return(0);
}

Int32
contents(AarParams * params)
{
  UChar		buf[BUFFERSIZ], buf2[BUFFERSIZ], verbose;
  UChar		verbosestr[MAXPATHLEN * 2 + 100], c;
  UChar		have_an_error, started, *cptr;
  Int32		type, i, uid, gid, ifd, rvr;
  Uns32		mode, lu;
  time_t	mtime, ltt;
  size_t	len, stt;
  FILE		*errfp;
  Int32		li;
  int		pid, pst, pp[2], ucfd;
  dev_t		rdev;
  void		(*verbosefunc)(UChar *, struct aar_params *);

  errfp = params->errfp;
  verbose = params->verbose;
  verbosefunc = params->verbosefunc;
  ifd = params->infd;

  started = 0;
  have_an_error = 0;
  pid = -1;

  forever{
    if(params->pre_verbosefunc)
	(*params->pre_verbosefunc)(NULL, params);

    i = get_int(params, &li);
    type = (Int32) li;

   tryagain:

    if(i < 1){
	if(i < 0)
	  return(EOF);

	i = formaterr(&type, params, started);
	have_an_error = 1;
	goto tryagain;
    }

    switch(type){
      case ENDOFARCHIVE:
	if(have_an_error){
	  i = formaterr(&type, params, started);
	  goto tryagain;
	}

	return(0);

      case INFORMATION:
	read_size_t(len, size_t);
	if(len + 1 > BUFFERSIZ)
	  cptr = NEWP(UChar, len + 1);
	else
	  cptr = buf;

	i = params->inputfunc(cptr, len, params);
	if(i < len)
	  goto eoferr;
	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}
	cptr[len] = '\0';
	verbosefunc(cptr, params);

	if(cptr != buf)
	  free(cptr);

	started = 1;
	have_an_error = 0;

	break;
	
      case DIRECTORY:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	sprintf(verbosestr, "%s%s\n", buf, verbose ? "/" : "");
	verbosefunc(verbosestr, params);

	started = 1;
	have_an_error = 0;

	break;

      case FIFO:
      case SOCKET:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < 1)
	  goto eoferr;
	buf[len] = '\0';

	sprintf(verbosestr, "%s%s\n", buf, verbose ?
				(type == FIFO ? "|" : "[") : "");
	verbosefunc(verbosestr, params);

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	break;

      case BLOCKDEVICE:
      case CHARDEVICE:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_uns(rdev, dev_t);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < 1)
	  goto eoferr;
	buf[len] = '\0';

	sprintf(verbosestr, "%s%s\n", buf, verbose ?
				(type == BLOCKDEVICE ? "#" : "*") : "");
	verbosefunc(verbosestr, params);

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	break;

      case HARDLINK:
      case SYMLINK:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	sprintf(verbosestr, "%s", buf);
	if(verbose)
	  sprintf(verbosestr + strlen(verbosestr), "%s  (%slink to ",
			(type == SYMLINK ? "@" : "="),
			(type == SYMLINK ? "symbolic " : ""));

	read_size_t(len, size_t);
	i = params->inputfunc(buf, len, params);
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	if(verbose)
	  sprintf(verbosestr + strlen(verbosestr), "%s)", buf);
	sprintf(verbosestr + strlen(verbosestr), "\n");
	verbosefunc(verbosestr, params);

	have_an_error = 0;
	started = 1;

	break;

      case REGFILE:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);	/* read filename */
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	read_size_t(len, size_t);		/* read uncompresscmd */
	i = params->inputfunc(buf2, len, params);
	if(i < len)
	  goto eoferr;
	buf2[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	read_size_t(len, size_t);			/* read filesize */

	if(!buf2[0] || !verbose)
	  sprintf(verbosestr, "%s\n", buf);
	else
	  sprintf(verbosestr, "%s  (to be uncompressed by %s)\n", buf, buf2);
	verbosefunc(verbosestr, params);

	ucfd = -1;
	if(params->check && buf2[0]){	/* check integrity of compressed */
	      i = pipe(pp);

	      if(i){
		fprintf(errfp,
			"Error: Cannot check file %s for integrity.\n",
				buf);
	      }
	      else{
		pid = fork_forced();

		if(pid < 0){
		  fprintf(errfp,
			"Error: Cannot check file %s for integrity.\n",
						buf);
		}
		else if(! pid){		/* child */
		  char		**unzipargv;
		  int		fd;

		  clr_timer();

		  close(pp[1]);

		  if(cmd2argvq(&unzipargv, buf2)){
		    close(pp[0]);
		    exit(1);
		  }

		  fd = open(NULLFILE, O_WRONLY | O_BINARY, 0600);
		  if(fd < 0)
		    exit(2);

		  dup2(pp[0], 0);
		  dup2(fd, 1);
		  dup2(fd, 2);

		  execvp(unzipargv[0], unzipargv + 1);

		  exit(3);
		}

		close(pp[0]);

		ucfd = pp[1];
	      }
	  }

	  forever{
	    if(len < COMMBUFSIZ){
	      i = params->inputfunc(buf, len, params);
	      if(i < len){
		i = formaterr(&type, params, started);
		have_an_error = 1;
		close(ucfd);
		goto tryagain;
	      }

	      if(ucfd >= 0)
		write_split(ucfd, buf, i);

	      break;
	    }

	    i = params->inputfunc(buf, COMMBUFSIZ, params);
	    if(i < COMMBUFSIZ){
	      i = formaterr(&type, params, started);
	      have_an_error = 1;
	      close(ucfd);
	      goto tryagain;
	    }

	    if(ucfd >= 0)
		write_split(ucfd, buf, i);

	    len -= COMMBUFSIZ;
	  }

	if(ucfd >= 0){
	  close(ucfd);

	  waitpid_forced(pid, &pst, 0);

	  if(WEXITSTATUS(pst)){
	    fprintf(stderr,
		"Integrity check: This compressed file seems to be corrupted.\n");
	  }
	}

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	break;

      case FILECONTENTS:
	read_time_t(mtime, time_t);

      case FILECONTENTS_O:
	read_size_t(len, size_t);
	i = params->inputfunc(buf, len, params);	/* read filename */
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	read_size_t(len, size_t);		/* read uncompresscmd */
	i = params->inputfunc(buf2, len, params);
	if(i < len)
	  goto eoferr;
	buf2[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	sprintf(verbosestr, "%s", buf);
	if(verbose)
	  strcat(verbosestr, "<");

	if(!buf2[0] || !verbose)
	  strcat(verbosestr, "\n");
	else{
	  cptr = verbosestr + strlen(verbosestr);
	  sprintf(cptr, "  (to be uncompressed by %s)\n", buf2);
	}
	verbosefunc(verbosestr, params);

	ucfd = -1;
	if(params->check && buf2[0]){	/* check integrity of compressed */
	      i = pipe(pp);

	      if(i){
		fprintf(errfp,
			"Error: Cannot check file %s for integrity.\n",
				buf);
	      }
	      else{
		pid = fork_forced();

		if(pid < 0){
		  fprintf(errfp,
			"Error: Cannot check file %s for integrity.\n",
						buf);
		}
		else if(! pid){		/* child */
		  char		**unzipargv;
		  int		fd;

		  clr_timer();

		  close(pp[1]);

		  if(cmd2argvq(&unzipargv, buf2)){
		    close(pp[0]);
		    exit(1);
		  }

		  fd = open(NULLFILE, O_WRONLY | O_BINARY, 0600);
		  if(fd < 0)
		    exit(2);

		  dup2(pp[0], 0);
		  dup2(fd, 1);
		  dup2(fd, 2);

		  execvp(unzipargv[0], unzipargv + 1);

		  exit(3);
		}

		close(pp[0]);

		ucfd = pp[1];
	      }
	  }

	do{
	  i = params->inputfunc(buf2, 1, params);
	  if(i < 1)
	    goto eoferr;
	  i = params->inputfunc(buf2 + 1, buf2[0], params);
	  if(i < buf2[0])
	    goto eoferr;

	  if(ucfd >= 0)
	    write_split(ucfd, buf2 + 1, i);

	} while(buf2[0] == (UChar) 0xff);

	if(ucfd >= 0){
	  close(ucfd);

	  waitpid_forced(pid, &pst, 0);

	  if(WEXITSTATUS(pst)){
	    fprintf(stderr,
		"Integrity check: This compressed file seems to be corrupted.\n");
	  }
	}

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	break;

      default:
	i = formaterr(&type, params, started);
	have_an_error = 1;
	goto tryagain;
    }
  }

  return(0);

 eoferr:

  fprintf(errfp, "Error: unexpected end of file.\n");

  return(EOF);
}

static Int32
make_basedir(UChar * name, Uns32 mode, Uns32 uid, Uns32 gid,
		AarParams * params)
{
  UChar		*cptr;
  struct stat	statb;
  Int32	res;
  FILE		*errfp;

  errfp = params->errfp;
  res = 0;

  cptr = FN_LASTDIRDELIM(name);
  if(cptr){
    if(cptr == name)
	return(0);

    *cptr = '\0';

    if(-1 == stat(name, &statb)){
	if( (res = make_basedir(name, mode, uid, gid, params)) ){
	  *cptr = FN_DIRSEPCHR;
	  return(-errno);
	}

	res = mkdir(name, mode);
	if(res){
	  fprintf(errfp, "Error: cannot create directory %s.\n", name);
	  *cptr = FN_DIRSEPCHR;
	  return(-errno);
	}

	if(!params->ignoreown){
	  res = chown(name, uid, gid);
	  if(res){
	    fprintf(errfp, "Error: cannot chown of directory %s.\n", name);
	    *cptr = FN_DIRSEPCHR;
	    return(-errno);
	  }
	}
    }

    *cptr = FN_DIRSEPCHR;

    return(res);
  }

  return(0);
}

void
set_props(UChar * buf, Int32 uid, Int32 gid,
		time_t mtime, Uns32 mode,
		AarParams * params)
{
  struct utimbuf	utim;

  if(!params->ignoreown){
    if(chown(buf, uid, gid)){
      fprintf(params->errfp, "Warning: cannot chown %s\n", buf);
    }
  }
  /*else*/{
    utim.actime = utim.modtime = mtime;
    if(utime(buf, &utim)){
	fprintf(params->errfp,
		"Warning: cannot set modificaton time on %s.\n", buf);
    }
    /*else*/{
	if(chmod(buf, mode))
	  fprintf(params->errfp,
		"Warning: cannot set permissions on %s.\n", buf);
    }
  }
}

static void
convtorel(UChar * buf, UChar rel)
{
  Int32	i;
  UChar		*cptr;

  cleanpath(buf);

  if(FN_ISABSPATH(buf) && rel){
    cptr = buf;
    cptr = FN_FIRSTDIRSEP(cptr);
    while(FN_ISDIRSEP(*cptr))
	cptr++;
    for(i = 0; *cptr; i++, cptr++)
	buf[i] = *cptr;
    buf[i] = '\0';
  }
}

static void
convtorelcwd(UChar * buf, UChar rel)
{
  Int32		i, n, len;
  UChar		*cptr, *cptr2;

  convtorel(buf, 0);

  if(!FN_ISABSPATH(buf) || !rel)
    return;

  n = -1;
  cptr = buf;
  while( (cptr = FN_FIRSTDIRSEP(cptr)) ){
    cptr++;
    n++;
    while(FN_ISDIRSEP(*cptr))
	cptr++;
    if(cptr[0] == '.'){
	if(FN_ISDIRSEP(cptr[1])){
	  n--;
	}
	else if(cptr[1] == '.'){
	  if(FN_ISDIRSEP(cptr[2])){
	    n -= 2;
	  }
	}
    }
  }

  len = strlen(buf);

  cptr = buf + len;
  cptr2 = cptr + n * 3 - 1;
  for(i = 0; i < len; i++)
    *(cptr2--) = *(cptr--);
  for(i = 0; i < n; i++){
    buf[i * 3] = buf[i * 3 + 1] = '.';
    buf[i * 3 + 2] = FN_DIRSEPCHR;
  }
}

Int32
readin(UChar ** filelist, AarParams * params, UChar * files_found)
{
  UChar		buf[BUFFERSIZ], buf2[BUFFERSIZ], fault;
  UChar		verbosestr[MAXPATHLEN * 2 + 100], c;
  UChar		started, have_an_error;
  Int32		type, i, j, gid, uid, fd, r, rvr, ifd;
  Uns32		mode, lu;
  time_t	mtime = 0, ltt;
  size_t	len, stt;
  FILE		*errfp;
  UChar		**files, verbose, skip, *cptr, **fileidx;
  Int32	li;
  dev_t		rdev;
  int		pid, pst, pp[2];
  int		num_written = 0;
  void		(*verbosefunc)(UChar *, struct aar_params *);
  struct stat	statb;

  verbose = params->verbose;
  verbosefunc = params->verbosefunc;

  files = filelist;
  i = r = 0;
  pid = -1;

  ifd = params->infd;

  if(files){
    while(*files)
      files++, i++;

    files = NEWP(UChar *, i + 1);
    if(!files)
      return(-ENOMEM);
    memset(files, 0, (i + 1) * sizeof(UChar *));

    j = i;
    while(i > 0){
      i--;
      cleanpath(filelist[i]);

      if(params->relative && FN_ISABSPATH(filelist[i])){
	cptr = filelist[i];
	cptr = FN_FIRSTDIRSEP(cptr);
	while(FN_ISDIRSEP(*cptr))
	  cptr++;
	files[i] = strdup(cptr);
      }
      else
	files[i] = strdup(filelist[i]);

      if(!files[i]){
	for(i++; i < j; i++)
	  free(files[i]);
	free(files);
	return(-ENOMEM);
      }
    }
  }

  errfp = params->errfp;

  started = 0;
  have_an_error = 0;

  forever{
    if(filelist && !params->recursive){
	for(fileidx = filelist, cptr = files_found;
					*fileidx; fileidx++, cptr++){
	  if(! (*cptr))
	    break;
	}

	if(! (*fileidx))
	  goto cleanup;
    }

    if(params->pre_verbosefunc)
	(*params->pre_verbosefunc)(NULL, params);

    i = get_int(params, &li);
    type = (Int32) li;

   tryagain:

    if(i < 1){
	if(i < 0){
	  r = EOF;
	  goto cleanup;
	}

	i = formaterr(&type, params, started);
	have_an_error = 1;
	goto tryagain;
    }

    skip = 0;

    switch(type){
      case ENDOFARCHIVE:
#if 0
	if(filelist){
	  for(fileidx = filelist, cptr = files_found;
					*fileidx; fileidx++, cptr++){
	    if(! (*cptr)){
		fprintf(params->errfp,
			"%s not found in archive.\n", *fileidx);
	    }
	  }
	}
#endif
	if(have_an_error){
	  i = formaterr(&type, params, started);
	  goto tryagain;
	}

	goto cleanup;

      case INFORMATION:
	read_size_t(len, size_t);
	if(len + 1 > BUFFERSIZ)
	  cptr = NEWP(UChar, len + 1);
	else
	  cptr = buf;

	i = params->inputfunc(cptr, len, params);
	if(i < len)
	  goto eoferr;
	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}
	cptr[len] = '\0';
	if(verbose)
	  verbosefunc(cptr, params);

	if(cptr != buf)
	  free(cptr);

	started = 1;
	have_an_error = 0;

	break;
	
      case DIRECTORY:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';
	convtorel(buf, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	if(!skip){
	  make_basedir(buf, mode, uid, gid, params);

	  if(mkdir(buf, mode)){
	    fprintf(errfp, "Error: cannot create directory %s\n", buf);
	  }
	  else{
	    set_props(buf, uid, gid, mtime, mode, params);
	    if(verbose){
		sprintf(verbosestr, "%s\n", buf);
		verbosefunc(verbosestr, params);
	    }

	  }
	}

	break;

#ifndef _WIN32
      case FIFO:
      case SOCKET:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';
	convtorel(buf, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	if(! skip){
	  make_basedir(buf, mode | 0100, uid, gid, params);

	  if(params->unlink)
	    unlink(buf);

	  if(mkfifo(buf, mode)){
	    fprintf(errfp, "Error: cannot create %s %s\n",
			(type == FIFO ? "named pipe" : "socket"), buf);
	  }
	  else{
	    set_props(buf, uid, gid, mtime, mode, params);
	    if(verbose){
		sprintf(verbosestr, "%s\n", buf);
		verbosefunc(verbosestr, params);
	    }
	  }
	}

	break;

      case BLOCKDEVICE:
      case CHARDEVICE:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_uns(rdev, dev_t);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';
	convtorel(buf, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	if(! skip){
	  make_basedir(buf, mode | 0100, uid, gid, params);

	  if(params->unlink)
	    unlink(buf);

	  if(mknod(buf, mode, rdev)){
	    fprintf(errfp, "Error: cannot create device %s\n", buf);
	  }
	  else{
	    set_props(buf, uid, gid, mtime, mode, params);
	    if(verbose){
		sprintf(verbosestr, "%s\n", buf);
		verbosefunc(verbosestr, params);
	    }
	  }
	}

	break;
#endif

      case HARDLINK:
      case SYMLINK:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < 1)
	  goto eoferr;
	buf[len] = '\0';
	convtorel(buf, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	read_int(len, Int32);
	i = params->inputfunc(buf2, len, params);
	if(i < len)
	  goto eoferr;
	buf2[len] = '\0';
	if(type == SYMLINK)
	  convtorelcwd(buf2, params->relative);
	else
	  convtorel(buf2, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	if(! skip){
	  if(params->unlink)
	    unlink(buf);

	  make_basedir(buf, mode | 0100, uid, gid, params);

	  if(type == HARDLINK){
	    if(link(buf2, buf)){
	      fprintf(errfp, "Error: cannot create link %s to %s.\n",
				buf, buf2);
	    }
	    else{
	      set_props(buf, uid, gid, mtime, mode, params);
	      if(verbose){
		sprintf(verbosestr, "%s\n", buf);
		verbosefunc(verbosestr, params);
	      }
	    }
	  }
	  if(type == SYMLINK){
	    if(symlink(buf2, buf)){
	      fprintf(errfp, "Error: cannot create symlink %s to %s.\n",
				buf, buf2);
	    }
	    else{
	      /*set_props(buf, uid, gid, mtime, mode, params);*/
#ifdef	HAVE_LCHOWN
	      if(!params->ignoreown){
		if(lchown(buf, uid, gid)){
		  fprintf(params->errfp, "Warning: cannot lchown %s\n", buf);
		}
	      }
#endif
	      if(verbose){
		sprintf(verbosestr, "%s\n", buf);
		verbosefunc(verbosestr, params);
	      }
	    }
	  }
	}

	break;

      case REGFILE:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);	/* read filename */
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';
	convtorel(buf, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	read_size_t(len, size_t);		/* read uncompresscmd */
	i = params->inputfunc(buf2, len, params);
	if(i < len)
	  goto eoferr;
	buf2[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	read_size_t(len, size_t);		/* read filesize */

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	if(!skip){
	  make_basedir(buf, mode | 0100, uid, gid, params);
	}

	fault = 0;
	fd = -10;

	if(skip)
	  fault = 1;

	if(! params->unlink && ! fault){
	  fd = open(buf, O_RDONLY | O_BINARY);
	  if(fd >= 0){
	    fprintf(errfp, "Error: must not delete existing %s.\n", buf);
	    fault = 1;
	    close(fd);
	  }
	}

	if(! buf2[0]){		/* not compressed */
	  if(!fault){
	    unlink(buf);

	    fd = open(buf, O_WRONLY | O_CREAT | O_BINARY, 0600);
	    if(fd < 0){
	      fd = -10;
	      fault = 1;
	      fprintf(errfp, "Error: Cannot create file %s.\n", buf);
	    }
	  }

	  forever{
	    if(len < COMMBUFSIZ){
	      i = params->inputfunc(buf2, len, params);
	      if(i < len){
		if(fd != -10)
		  close(fd);
		goto eoferr;
	      }
	      if(!fault){
	        if(write_split(fd, buf2, len)){
		  fprintf(errfp, "Error: writing to %s failed.\n", buf);
	        }
	      }
	      break;
	    }

	    i = params->inputfunc(buf2, COMMBUFSIZ, params);
	    if(i < COMMBUFSIZ){
	      if(fd != -10)
	        close(fd);
	      goto eoferr;
	    }
	    if(!fault){
	      if(write_split(fd, buf2, COMMBUFSIZ)){
	        fprintf(errfp, "Error: writing to %s failed.\n", buf);
		if(fd != -10)
	          close(fd);
	        fault = 1;
		fd = -10;;
	      }
	    }

	    len -= COMMBUFSIZ;
	  }

	  if(fd != -10)
	    close(fd);
	}
	else{			/* compressed */
	  if(!fault){
	    unlink(buf);

	    fd = open(buf, O_WRONLY | O_CREAT | O_BINARY, 0600);
	    if(fd < 0){
		fault = 1;
		fprintf(errfp, "Error: Cannot create file %s.\n", buf);
	    }
	    else{
	      close(fd);
	      fd = -1;

	      i = pipe(pp);

	      if(i){
		fault = 1;
		fprintf(errfp,
			"Error: Cannot create pipe for uncompressing %s.\n",
				buf);
	      }
	      else{
		pid = fork_forced();

		if(pid < 0){
		  fault = 1;
		  fprintf(errfp, "Error: Cannot create file %s.\n", buf);
		}
		else if(! pid){		/* child */
		  char		**unzipargv;

		  clr_timer();

		  close(pp[1]);

		  if(cmd2argvq(&unzipargv, buf2)){
		    close(pp[0]);
		    exit(1);
		  }

		  fd = open(buf, O_WRONLY | O_CREAT | O_BINARY, 0600);
		  if(fd < 0)
		    exit(2);

		  dup2(pp[0], 0);
		  dup2(fd, 1);

		  execvp(unzipargv[0], unzipargv + 1);

		  exit(3);
		}

		close(pp[0]);

		fd = pp[1];
	      }
	    }
	  }

	  forever{
	    if(len < COMMBUFSIZ){
	      i = params->inputfunc(buf2, len, params);
	      if(i < len){
		if(fd >= 0){
		  kill(pid, SIGTERM);
		  waitpid_forced(pid, &pst, 0);
		  close(fd);
		}
		goto eoferr;
	      }
	      if(!fault){
	        if(write_split(fd, buf2, len)){
		  fprintf(errfp, "Error: writing to %s failed.\n", buf);
	        }
	      }

	      break;
	    }

	    i = params->inputfunc(buf2, COMMBUFSIZ, params);
	    if(i < COMMBUFSIZ){
	      if(fd >= 0){
		kill(pid, SIGTERM);
		waitpid_forced(pid, &pst, 0);
		close(fd);
	      }
	      goto eoferr;
	    }
	    if(!fault){
	      if(write_split(fd, buf2, COMMBUFSIZ)){
	        fprintf(errfp, "Error: writing to %s failed.\n", buf);
	        if(fd >= 0){
		  kill(pid, SIGTERM);
		  waitpid_forced(pid, &pst, 0);
		  close(fd);
		}
	        fd = -1;
		fault = 1;
	      }
	    }

	    len -= COMMBUFSIZ;
	  }

	  if(fd >= 0){
	    close(fd);
	    waitpid_forced(pid, &pst, 0);
	  }
	}

	if(!skip && !fault){
	  set_props(buf, uid, gid, mtime, mode, params);

	  if(verbose){
	    sprintf(verbosestr, "%s\n", buf);
	    verbosefunc(verbosestr, params);
	  }
	}

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	break;

      case FILECONTENTS:
	read_time_t(mtime, time_t);

      case FILECONTENTS_O:
	read_size_t(len, size_t);
	i = params->inputfunc(buf, len, params);	/* read filename */
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	read_size_t(len, size_t);		/* read uncompresscmd */
	i = params->inputfunc(buf2, len, params);
	if(i < len)
	  goto eoferr;
	buf2[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	i = stat(buf, &statb);
	uid = statb.st_uid;
	if(i){
	  fprintf(errfp, "Error: Cannot write to file %s.\n", buf);
	  skip = 1;
	}

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	fd = -10;
	fault = 0;
	pid = -1;

	if(! skip){
	  fd = open(buf, O_WRONLY | O_BINARY);
	  if(fd < 0){
	    fd = -10;
	    fault = 1;
	    fprintf(errfp, "Error: Cannot write to file %s.\n", buf);
	  }

	  if(buf2[0] && !fault){	/* have to uncompress */
	    i = pipe(pp);
	    if(i){
		fprintf(errfp,
			"Error: cannot uncompress contents of file %s.\n",
			buf);
		skip = 1;
	    }
	    else{
		pid = fork_forced();

		if(pid < 0){
		  fault = 1;
		  fprintf(errfp,
			"Error: Cannot uncompress to file %s.\n", buf);
		}
		else if(! pid){		/* child */
		  char		**unzipargv;

		  clr_timer();

		  close(pp[1]);

		  if(cmd2argvq(&unzipargv, buf2)){
		    close(pp[0]);
		    exit(1);
		  }

		  dup2(pp[0], 0);
		  dup2(fd, 1);

		  execvp(unzipargv[0], unzipargv + 1);

		  exit(3);
		}

		close(pp[0]);
		close(fd);
		fd = pp[1];
	    }
	  }
	}

	if(skip)
	  fault = 1;

	do{
	  i = params->inputfunc(buf2, 1, params);
	  if(i < 1)
	    goto eoferr;
	  i = params->inputfunc(buf2 + 1, buf2[0], params);
	  if(i > 0 && ! fault){
	    j = write_split(fd, buf2 + 1, i);
	    num_written += i;

	    if(j){
		fprintf(errfp, "Error: writing to %s failed.\n", buf);
		fault = 1;
		close(fd);
		fd = -10;
	    }
	  }

	  if(i < buf2[0]){
	    if(fd >= 0)
		close(fd);
	    goto eoferr;
	  }
	} while(buf2[0] == (UChar) 0xff);

	if(fd >= 0)
	  close(fd);

	if(pid >= 0){
	  waitpid_forced(pid, &pst, 0);
	  if(WEXITSTATUS(pst)){
	    fprintf(errfp, "Error: uncompressing to %s failed.\n", buf);
	    fault = 1;
	  }
	}

	if(verbose && !skip && !fault){
	  sprintf(verbosestr, "%s\n", buf);
	  verbosefunc(verbosestr, params);
	}

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	break;

      default:
	i = formaterr(&type, params, started);
	goto tryagain;
    }
  }

 cleanup:

  if(files){
    for(fileidx = files; *fileidx; fileidx++)
	free(*fileidx);

    free(files);
  }

  return(r);

 eoferr:

  if(files){
    for(fileidx = files; *fileidx; fileidx++)
	free(*fileidx);

    free(files);
  }

  fprintf(errfp, "Error: unexpected end of file.\n");

  return(EOF);
}

static void
print_if_false(
  UChar		*name,
  UChar		*type_n,
  UChar		*false,
  AarParams	*params)
{
  UChar		verbosestr[MAXPATHLEN * 2 + 100];

  if(! *false){
    sprintf(verbosestr, "%s%s\n", name, type_n);
    params->verbosefunc(verbosestr, params);
    *false = 1;
  }
}

static void
print_if_unequal_u(
  Uns32		is,
  Uns32		should,
  UChar		*paramname,
  UChar		*name,
  UChar		*tname,
  UChar		*false,
  AarParams	*params)
{
  UChar		verbosestr[MAXPATHLEN * 2 + 100];

  if(is == should)
    return;

  print_if_false(name, tname, false, params);
  sprintf(verbosestr, DP "%s is %lu, should be %lu.\n", paramname,
		(unsigned long) is, (unsigned long) should);
  params->verbosefunc(verbosestr, params);
}

static void
print_if_unequal_i(
  Int32		is,
  Int32		should,
  UChar		*paramname,
  UChar		*name,
  UChar		*tname,
  UChar		*false,
  AarParams	*params)
{
  UChar		verbosestr[MAXPATHLEN * 2 + 100];

  if(is == should)
    return;

  print_if_false(name, tname, false, params);
  sprintf(verbosestr, DP "%s is %ld, should be %ld.\n", paramname,
		(long int) is, (long int) should);
  params->verbosefunc(verbosestr, params);
}

static void
print_if_unequal_t(
  time_t	is,
  time_t	should,
  UChar		*paramname,
  UChar		*name,
  UChar		*tname,
  UChar		*false,
  AarParams	*params)
{
  UChar		verbosestr[MAXPATHLEN * 2 + 100], timestr1[50], timestr2[50];

  if(is == should)
    return;

  print_if_false(name, tname, false, params);
  sprintf(verbosestr, DP "%s is %s, should be %s.\n", paramname,
			(char *) time_t_to_intstr(is, timestr1),
			(char *) time_t_to_intstr(should, timestr2));
  params->verbosefunc(verbosestr, params);
}

static void
print_if_unequal_s(
  UChar		*is,
  UChar		*should,
  UChar		*paramname,
  UChar		*name,
  UChar		*tname,
  UChar		*false,
  AarParams	*params)
{
  UChar		verbosestr[MAXPATHLEN * 2 + 100];

  if(!strcmp(is, should))
    return;

  print_if_false(name, tname, false, params);
  sprintf(verbosestr, DP "%s is %s, should be %s.\n", paramname,
		(char *) is, (char *) should);
  params->verbosefunc(verbosestr, params);
}

#define	SUBP_CHUNKSIZE	BUFFERSIZ

Int32
verify(UChar ** filelist, AarParams * params, UChar * files_found)
{
  UChar		buf[BUFFERSIZ], buf2[BUFFERSIZ], buf3[BUFFERSIZ];
  UChar		verbosestr[MAXPATHLEN * 2 + 100], name_printed;
  UChar		started, have_an_error, vbuf[BUFFERSIZ], c, fault;
  UChar		*typename, *typetag, subprfault, compressed, file_exh;
  UChar		**files, verbose, skip, *cptr, *cptr2, **fileidx;
  Int32		li, type, i, j, n, gid, uid, fd, r, rvr, ifd, to_read;
  Int32		to_compare, bustream_exh, written_bytes, remaining_bytes;
  size_t	compared_bytes, read_bytes, filesize, flen;
  UChar		sizestr1[30], sizestr2[30];
  Int32		wb, rb;
  Uns32		mode, lu;
  time_t	mtime = 0, ltt;
  size_t	len, stt;
  FILE		*errfp;
  dev_t		rdev;
  int		pid, pst, inpp[2], outpp[2];
  void		(*verbosefunc)(UChar *, struct aar_params *);
  struct stat	statb, statb2, statb3;
  struct timeval	tv;

  verbose = params->verbose;
  verbosefunc = params->verbosefunc;

  files = filelist;
  i = r = 0;
  flen = 0;
  pid = -1;

  ifd = params->infd;

  if(files){
    while(*files)
      files++, i++;

    files = NEWP(UChar *, i + 1);
    if(!files)
      return(-ENOMEM);
    memset(files, 0, (i + 1) * sizeof(UChar *));

    j = i;
    while(i > 0){
      i--;
      cleanpath(filelist[i]);

      if(params->relative && FN_ISABSPATH(filelist[i])){
	cptr = filelist[i];
	cptr = FN_FIRSTDIRSEP(cptr);
	while(FN_ISDIRSEP(*cptr))
	  cptr++;
	files[i] = strdup(cptr);
      }
      else
	files[i] = strdup(filelist[i]);

      if(!files[i]){
	for(i++; i < j; i++)
	  free(files[i]);
	free(files);
	return(-ENOMEM);
      }
    }
  }

  errfp = params->errfp;

  started = 0;
  have_an_error = 0;

  forever{
    if(filelist && !params->recursive){
	for(fileidx = filelist, cptr = files_found;
					*fileidx; fileidx++, cptr++){
	  if(! (*cptr))
	    break;
	}

	if(! (*fileidx))
	  goto cleanup;
    }

    if(params->pre_verbosefunc)
	(*params->pre_verbosefunc)(NULL, params);

    i = get_int(params, &li);
    type = (Int32) li;

   tryagain:

    if(i < 1){
	if(i < 0){
	  r = EOF;
	  goto cleanup;
	}

	i = formaterr(&type, params, started);
	have_an_error = 1;
	goto tryagain;
    }

    skip = 0;
    name_printed = 0;

    switch(type){
      case ENDOFARCHIVE:
#if 0
	if(filelist){
	  for(fileidx = filelist, cptr = files_found;
					*fileidx; fileidx++, cptr++){
	    if(! (*cptr)){
		fprintf(params->errfp,
			DP "%s not found in archive.\n", *fileidx);
	    }
	  }
	}
#endif
	if(have_an_error){
	  i = formaterr(&type, params, started);
	  goto tryagain;
	}

	goto cleanup;

      case INFORMATION:
	read_size_t(len, size_t);
	if(len + 1 > BUFFERSIZ)
	  cptr = NEWP(UChar, len + 1);
	else
	  cptr = buf;

	i = params->inputfunc(cptr, len, params);
	if(i < len)
	  goto eoferr;
	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}
	cptr[len] = '\0';
	if(verbose)
	  verbosefunc(cptr, params);

	if(cptr != buf)
	  free(cptr);

	started = 1;
	have_an_error = 0;

	break;
	
      case DIRECTORY:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';
	convtorel(buf, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	if(!skip){
	  typename = "directory";
	  typetag = "/";

	  if(verbose){
	    print_if_false(buf, typetag, &name_printed, params);
	  }
	  if(stat(buf, &statb)){
	    print_if_false(buf, typetag, &name_printed, params);
	    sprintf(verbosestr, "Cannot stat %s.\n", buf);
	    verbosefunc(verbosestr, params);
	  }
	  else{
	    if(!IS_DIRECTORY(statb)){
		print_if_false(buf, typetag, &name_printed, params);
		sprintf(verbosestr, DP "Is not a %s.\n", typename);
		verbosefunc(verbosestr, params);
	    }
	    else{
		print_if_unequal_u(statb.st_mode, mode, "Mode", buf,
			typetag, &name_printed, params);
		print_if_unequal_i(statb.st_uid, uid, "User-ID", buf,
			typetag, &name_printed, params);
		print_if_unequal_i(statb.st_gid, gid, "Group-ID", buf,
			typetag, &name_printed, params);
		print_if_unequal_t(statb.st_mtime, mtime,
			"Modification-Time", buf,
			typetag, &name_printed, params);
	    }
	  }
	}

	break;

#ifndef _WIN32
      case FIFO:
      case SOCKET:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';
	convtorel(buf, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	if(! skip){
	  typename = (type == FIFO ? "Named Pipe" : "Socket");
	  typetag = (type == FIFO ? "|" : "[");

	  if(verbose){
	    print_if_false(buf, typetag, &name_printed, params);
	  }
	  if(stat(buf, &statb)){
	    print_if_false(buf, typetag, &name_printed, params);
	    sprintf(verbosestr, "Cannot stat %s.\n", buf);
	    verbosefunc(verbosestr, params);
	  }
	  else{
	    if(!(type == FIFO ? IS_FIFO(statb) : IS_SOCKET(statb))){
		print_if_false(buf, typetag, &name_printed, params);
		sprintf(verbosestr, DP "Is not a %s.\n", typename);
		verbosefunc(verbosestr, params);
	    }
	    else{
		print_if_unequal_u(statb.st_mode, mode, "Mode", buf,
			typetag, &name_printed, params);
		print_if_unequal_i(statb.st_uid, uid, "User-ID", buf,
			typetag, &name_printed, params);
		print_if_unequal_i(statb.st_gid, gid, "Group-ID", buf,
			typetag, &name_printed, params);
		print_if_unequal_t(statb.st_mtime, mtime,
			"Modification-Time", buf,
			typetag, &name_printed, params);
	    }
	  }
	}

	break;

      case BLOCKDEVICE:
      case CHARDEVICE:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_uns(rdev, dev_t);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';
	convtorel(buf, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	if(! skip){
	  typename = (type == CHARDEVICE ? "Character Device" : "Block Device");
	  typetag = (type == CHARDEVICE ? "*" : "#");

	  if(verbose){
	    print_if_false(buf, typetag, &name_printed, params);
	  }
	  if(stat(buf, &statb)){
	    print_if_false(buf, typetag, &name_printed, params);
	    sprintf(verbosestr, "Cannot stat %s.\n", buf);
	    verbosefunc(verbosestr, params);
	  }
	  else{
	    if(!(type == CHARDEVICE ? IS_CHARDEV(statb)
					: IS_BLOCKDEV(statb))){
		print_if_false(buf, typetag, &name_printed, params);
		sprintf(verbosestr, DP "Is not a %s.\n", typename);
		verbosefunc(verbosestr, params);
	    }
	    else{
		print_if_unequal_u(statb.st_mode, mode, "Mode", buf,
			typetag, &name_printed, params);
		print_if_unequal_i(statb.st_uid, uid, "User-ID", buf,
			typetag, &name_printed, params);
		print_if_unequal_i(statb.st_gid, gid, "Group-ID", buf,
			typetag, &name_printed, params);
		print_if_unequal_t(statb.st_mtime, mtime,
			"Modification-Time", buf,
			typetag, &name_printed, params);
		print_if_unequal_u(statb.st_rdev, rdev,
			"Major number", buf,
			typetag, &name_printed, params);
	    }
	  }
	}

	break;
#endif

      case SYMLINK:
      case HARDLINK:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);
	if(i < 1)
	  goto eoferr;
	buf[len] = '\0';
	convtorel(buf, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	read_size_t(len, size_t);
	i = params->inputfunc(buf2, len, params);
	if(i < len)
	  goto eoferr;
	buf2[len] = '\0';
	convtorelcwd(buf2, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	if(! skip){
	  typename = (type == SYMLINK ? "Symlink" : "Hardlink");
	  typetag = (type == SYMLINK ? "@" : "=");

	  if(verbose){
	    print_if_false(buf, typetag, &name_printed, params);
	  }
	  if(lstat(buf, &statb)){
	    print_if_false(buf, typetag, &name_printed, params);
	    sprintf(verbosestr, "Cannot stat %s.\n", buf);
	    verbosefunc(verbosestr, params);
	  }
	  else{
	    if(!(type == SYMLINK ? IS_SYMLINK(statb) : IS_HARDLINK(statb))){
		print_if_false(buf, typetag, &name_printed, params);
		sprintf(verbosestr, DP "Is not a %s.\n", typename);
		verbosefunc(verbosestr, params);
	    }
	    else{
		if(type == SYMLINK){
		  i = readlink(buf, buf3, BUFFERSIZ);
		  buf3[i] = '\0';

		  if(!FN_ISABSPATH(buf3) && FN_ISPATH(buf)){
		    strcpy(vbuf, buf);
		    strcpy(FN_LASTDIRDELIM(vbuf) + 1, buf3);
		    strcpy(buf3, vbuf);
		  }
		  if(!FN_ISABSPATH(buf2) && FN_ISPATH(buf)){
		    strcpy(vbuf, buf);
		    strcpy(FN_LASTDIRDELIM(vbuf) + 1, buf2);
		    strcpy(buf2, vbuf);
		  }
		}
		else
		  strcpy(buf3, buf2);

		i = stat(buf3, &statb3);
		j = stat(buf2, &statb2);
		if(!i && !j){
		  if(statb2.st_ino != statb3.st_ino
			|| statb2.st_rdev != statb3.st_rdev){
		    print_if_unequal_s(buf3, buf2, "File pointed to",
			buf, typetag, &name_printed, params);
		  }
		}
		if(i || j){
		  print_if_unequal_s(buf3, buf2, "File pointed to",
			buf, typetag, &name_printed, params);
		}

		print_if_unequal_u(statb.st_mode, mode, "Mode", buf,
			typetag, &name_printed, params);
		print_if_unequal_i(statb.st_uid, uid, "User-ID", buf,
			typetag, &name_printed, params);
		print_if_unequal_i(statb.st_gid, gid, "Group-ID", buf,
			typetag, &name_printed, params);
		print_if_unequal_t(statb.st_mtime, mtime,
			"Modification-Time", buf,
			typetag, &name_printed, params);
	    }
	  }
	}

	break;

      case REGFILE:
	read_uns(mode, Uns32);
	read_time_t(mtime, time_t);
	read_int(uid, Int32);
	read_int(gid, Int32);
	read_size_t(len, size_t);

	i = params->inputfunc(buf, len, params);	/* read filename */
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';
	convtorel(buf, params->relative);

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	read_size_t(len, size_t);		/* read uncompresscmd */
	i = params->inputfunc(buf2, len, params);
	if(i < len)
	  goto eoferr;
	buf2[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	read_size_t(len, size_t);			/* read filesize */

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	typename = "Regular File";
	typetag = "";

	if(!skip){
	  if(verbose){
	    print_if_false(buf, typetag, &name_printed, params);
	  }
	  if(stat(buf, &statb)){
	    print_if_false(buf, typetag, &name_printed, params);
	    sprintf(verbosestr, DP "Cannot stat %s\n", buf);
	    verbosefunc(verbosestr, params);
	    skip = 1;
	  }
	  else{
	    if(!IS_REGFILE(statb)){
		print_if_false(buf, typetag, &name_printed, params);
		sprintf(verbosestr, DP "Is not a %s.\n", typename);
		verbosefunc(verbosestr, params);
		skip = 1;
	    }
	    else{
		flen = statb.st_size;
		print_if_unequal_u(statb.st_mode, mode, "Mode", buf,
			typetag, &name_printed, params);
		print_if_unequal_i(statb.st_uid, uid, "User-ID", buf,
			typetag, &name_printed, params);
		print_if_unequal_i(statb.st_gid, gid, "Group-ID", buf,
			typetag, &name_printed, params);
		print_if_unequal_t(statb.st_mtime, mtime,
			"Modification-Time", buf,
			typetag, &name_printed, params);
	    }
	  }
	}

	fault = subprfault = 0;
	fd = -1;

	if(skip)
	  fault = 1;

	if(!fault){
	  fd = open(buf, O_RDONLY | O_BINARY);
	  if(fd < 0){
	    fault = 1;

	    sprintf(verbosestr, DP "Cannot open %s\n", buf);
	    verbosefunc(verbosestr, params);
	  }
	}

	compressed = buf2[0];

	if(compressed){
	  i = pipe(inpp);
	  j = pipe(outpp);
	  if(i || j){
	    subprfault = 1;
	    fprintf(errfp,
		"Error: Cannot create pipe for uncompression of %s.\n",
				buf);
	    if(!i){
	      close(inpp[0]);
	      close(inpp[1]);
	    }
	  }

	  if(!subprfault){
	    pid = fork_forced();
	    if(pid < 0){
	      fprintf(errfp, "Error: Cannot start uncompression of %s.\n", buf);
	      subprfault = 1;
	    }
	    if(!pid){		/* child */
	      char	**unzipargv;

	      close(inpp[1]);
	      close(outpp[0]);

	      if(cmd2argvq(&unzipargv, buf2)){
		close(inpp[0]);
		close(outpp[1]);
		exit(1);
	      }

	      dup2(inpp[0], 0);
	      dup2(outpp[1], 1);

	      execvp(unzipargv[0], unzipargv + 1);
	      exit(3);
	    }
	  }
	  close(inpp[0]);
	  close(outpp[1]);
	  if(subprfault){
	    while(len > 0){
		i = params->inputfunc(buf3,
			len > BUFFERSIZ ? BUFFERSIZ : len, params);
		if(i < 0)
		  break;
		len -= (i > 0 ? i : 0);
	    }
	    len = 0;
	  }

	  fcntl(inpp[1], F_SETFL, fcntl(inpp[1], F_GETFL) | O_NONBLOCK);
	  fcntl(outpp[0], F_SETFL, fcntl(outpp[0], F_GETFL) | O_NONBLOCK);
	}

	read_bytes = compared_bytes = written_bytes = remaining_bytes = 0;
	bustream_exh = file_exh = 0;
	while(!bustream_exh){
	  if(!compressed){		/* read a bufferfull from the backup */
	    to_compare = to_read = (len > SUBP_CHUNKSIZE ? SUBP_CHUNKSIZE : len);
	    i = params->inputfunc(buf3, to_read, params);
	    if(i < to_read){
		goto formaterr_verify_regf;	/* sorry for that goto */
	    }

	    read_bytes += to_read;
	    len -= (i > 0 ? i : 0);
	    if(len < 1)
		bustream_exh = 1;
	  }
	  else{				/* backup is compressed */
	    forever{
	      to_read = to_compare = SUBP_CHUNKSIZE;

	      rb = wb = read(outpp[0], buf3, to_read);

	      POSZ(rb);		/* it does absolutely not matter */
				/* why we were unable to read */
	      if(rb > 0 || pid < 0){
		if(!rb){
		  bustream_exh = 1;
		}

		read_bytes += rb;
		to_compare = rb;

		break;
	      }
	      else{
		if(len > 0){
		  if(remaining_bytes)
		    n = remaining_bytes;
		  else{
		    n = params->inputfunc(buf2, i = (len > SUBP_CHUNKSIZE ?
					SUBP_CHUNKSIZE : len), params);
		    if(n < i)
			goto formaterr_verify_regf;

		    written_bytes = 0;
		  }

		  wb = write(inpp[1], buf2 + written_bytes, n);
		  POSZ(wb);

		  remaining_bytes = n - wb;
		  if(remaining_bytes)
		    written_bytes += wb;

		  len -= wb;
		}
		else{
		  if(inpp[1] >= 0){
		    close(inpp[1]);
		    inpp[1] = -1;
		  }
		  if(inpp[1] < 0)
		    if(waitpid(pid, &pst, WNOHANG) > 0)
			pid = -1;
		}
	      }

	      if(wb < 1 && pid >= 0){		/* uncompress program busy */
		SETZERO(tv);		/* busy, sleep to give it the CPU */
		tv.tv_usec = 10000;
		select(0, NULL, NULL, NULL, &tv);	/* "sleep" */
	      }
	    }		/* forever try to read and/or write */
	  }

	  if(!file_exh && !fault){	/* read a bufferfull from the file to compare */
	    n = read_forced(fd, vbuf, to_compare);
	    POSZ(n);
	    if(n < to_compare)
		file_exh = 1;

	    i = memcmp(vbuf, buf3, n);		/* compare buffers */
	    if(i){
		for(i = 0, cptr = vbuf, cptr2 = buf3;
				*cptr == *cptr2 && i < n;
					i++, cptr++, cptr2++);

		print_if_false(buf, typetag, &name_printed, params);
		sprintf(verbosestr, DP "File differs from position %s.\n",
			size_t_to_intstr(compared_bytes + i + 1, sizestr1));
		verbosefunc(verbosestr, params);

		file_exh = 1;
	    }

	    compared_bytes += n;

	    flen -= n;
	  }
	}

	close(fd);

	if(compressed){
	  if(inpp[1] >= 0)
	    close(inpp[1]);
	  close(outpp[0]);

	  if(pid >= 0)
	    waitpid_forced(pid, &pst, 0);
	  pst = WEXITSTATUS(pst);
	  if(pst){
	    print_if_false(buf, typetag, &name_printed, params);
	    sprintf(verbosestr, " Error:Uncompressing the stored file failed.\n");
	  }
	}

	if(flen > 0 && !fault){
	  print_if_false(buf, typetag, &name_printed, params);
	  sprintf(verbosestr,
			DP "File is longer (%s) than stored version (%s).\n",
			size_t_to_intstr(statb.st_size, sizestr1),
			size_t_to_intstr(read_bytes, sizestr2));
	  verbosefunc(verbosestr, params);
	}

	if(statb.st_size < read_bytes && !fault){
	  print_if_false(buf, typetag, &name_printed, params);
	  sprintf(verbosestr,
			DP "File is shorter (%s) than stored version (%s).\n",
			size_t_to_intstr(statb.st_size, sizestr1),
			size_t_to_intstr(read_bytes, sizestr2));
	  verbosefunc(verbosestr, params);
	}

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	break;

       formaterr_verify_regf:
	if(compressed){
	  if(inpp[1] >= 0)
	    close(inpp[1]);
	  close(outpp[0]);
	  if(pid >= 0){
	    kill(pid, SIGTERM);
	    waitpid(pid, &pst, 0);
	  }
	}
	close(fd);

	i = formaterr(&type, params, started);
	have_an_error = 1;
	goto tryagain;

	break;

      case FILECONTENTS:
	read_time_t(mtime, time_t);

      case FILECONTENTS_O:
	read_size_t(len, size_t);
	i = params->inputfunc(buf, len, params);	/* read filename */
	if(i < len)
	  goto eoferr;
	buf[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	read_size_t(len, size_t);		/* read uncompresscmd */
	i = params->inputfunc(buf2, len, params);
	if(i < len)
	  goto eoferr;
	buf2[len] = '\0';

	i = params->inputfunc(&c, 1, params);
	if(c != ';' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	i = stat(buf, &statb);
	uid = statb.st_uid;
	if(i){
	  fprintf(errfp, "Error: Cannot read file %s.\n", buf);
	  skip = 1;
	}

	if(! name_in_list(buf, files, params->recursive, files_found)
			|| invalid_time_or_uid(mtime, uid, params)
			|| (params->uid && not_allowed(buf, params->uid)))
	  skip = 1;

	name_in_list(buf, files, 0, files_found);

	typename = "Filecontents";
	typetag = "<";

	if(!skip){
	  if(verbose){
	    print_if_false(buf, typetag, &name_printed, params);
	  }
	}

	fault = subprfault = 0;
	fd = -1;

	if(skip)
	  fault = 1;

	if(!fault){
	  fd = open(buf, O_RDONLY | O_BINARY);
	  if(fd < 0){
	    fault = 1;

	    sprintf(verbosestr, DP "Cannot open %s\n", buf);
	    verbosefunc(verbosestr, params);
	  }
	}

	compressed = buf2[0];

	if(compressed){
	  i = pipe(inpp);
	  j = pipe(outpp);
	  if(i || j){
	    subprfault = 1;
	    fprintf(errfp,
		"Error: Cannot create pipe for uncompression of %s.\n",
					buf);
	    if(!i){
	      close(inpp[0]);
	      close(inpp[1]);
	    }
	  }

	  if(!subprfault){
	    pid = fork_forced();
	    if(pid < 0){
	      fprintf(errfp, "Error: Cannot start uncompression of %s.\n", buf);
	      subprfault = 1;
	    }
	    if(!pid){		/* child */
	      char	**unzipargv;

	      close(inpp[1]);
	      close(outpp[0]);

	      if(cmd2argvq(&unzipargv, buf2)){
		close(inpp[0]);
		close(outpp[1]);
		exit(1);
	      }

	      dup2(inpp[0], 0);
	      dup2(outpp[1], 1);

	      execvp(unzipargv[0], unzipargv + 1);
	      exit(3);
	    }
	  }
	  close(inpp[0]);
	  close(outpp[1]);
	  if(subprfault){
	    while(len > 0){
		i = params->inputfunc(buf3,
			len > BUFFERSIZ ? BUFFERSIZ : len, params);
		if(i < 0)
		  break;
		len -= (i > 0 ? i : 0);
	    }
	    len = 0;
	  }

	  fcntl(inpp[1], F_SETFL, fcntl(inpp[1], F_GETFL) | O_NONBLOCK);
	  fcntl(outpp[0], F_SETFL, fcntl(outpp[0], F_GETFL) | O_NONBLOCK);
	}

	read_bytes = filesize = compared_bytes = written_bytes
						= remaining_bytes = 0;
	bustream_exh = file_exh = 0;
	c = 0xff;
	while(!bustream_exh){
	  if(!compressed){		/* read <= 255 bytes from the backup */
	    i = params->inputfunc(&c, 1, params);
	    if(i < 1){
		goto formaterr_verify_fcont;
	    }
	    to_compare = to_read = c;
	    i = params->inputfunc(buf3, to_read, params);
	    if(i < to_read){
		goto formaterr_verify_fcont;
	    }

	    read_bytes += to_read;
	    if(c < 0xff)
		bustream_exh = 1;
	  }
	  else{				/* backup is compressed */
	    forever{
	      to_read = to_compare = SUBP_CHUNKSIZE;

	      rb = wb = read(outpp[0], buf3, to_read);

	      POSZ(rb);		/* it does absolutely not matter */
				/* why we were unable to read */
	      if(rb > 0 || pid < 0){
		if(!rb){
		  bustream_exh = 1;
		}

		read_bytes += rb;
		to_compare = rb;

		break;
	      }
	      else{
		if(c == 0xff){
		  if(remaining_bytes)
		    n = remaining_bytes;
		  else{
		    n = params->inputfunc(&c, 1, params);
		    if(n < 1)
			goto formaterr_verify_fcont;
		    n = params->inputfunc(buf2, c, params);
		    if(n < c)
			goto formaterr_verify_fcont;

		    written_bytes = 0;
		  }

		  wb = write(inpp[1], buf2 + written_bytes, n);
		  POSZ(wb);

		  remaining_bytes = n - wb;
		  if(remaining_bytes)
		    written_bytes += wb;
		}
		else{
		  if(inpp[1] >= 0){
		    close(inpp[1]);
		    inpp[1] = -1;
		  }
		  if(inpp[1] < 0)
		    if(waitpid(pid, &pst, WNOHANG) > 0)
			pid = -1;
		}
	      }

	      if(wb < 1 && pid >= 0){		/* uncompress program busy */
		SETZERO(tv);			/* sleep to give it the CPU */
		tv.tv_usec = 10000;
		select(0, NULL, NULL, NULL, &tv);	/* "sleep" */
	      }
	    }		/* forever try to read and/or write */
	  }

	  if(!file_exh){	/* read a bufferfull from the file to compare */
	    n = read_forced(fd, vbuf, to_compare);
	    POSZ(n);
	    filesize += n;
	    if(n < to_compare)
		file_exh = 1;

	    if(!fault){
	      i = memcmp(vbuf, buf3, n);		/* compare buffers */
	      if(i){
		for(i = 0, cptr = vbuf, cptr2 = buf3;
				*cptr == *cptr2 && i < n;
					i++, cptr++, cptr2++);

		print_if_false(buf, typetag, &name_printed, params);
		sprintf(verbosestr, DP "Filecontents differ from position %s.\n",
			size_t_to_intstr(compared_bytes + i + 1, sizestr1));
		verbosefunc(verbosestr, params);

		fault = 1;
	      }

	      compared_bytes += n;
	    }
	  }
	}

	while((i = read(fd, vbuf, BUFFERSIZ)) > 0)
	  filesize += i;

	close(fd);

	if(compressed){
	  if(inpp[1] >= 0)
	    close(inpp[1]);
	  close(outpp[0]);

	  if(pid >= 0)
	    waitpid_forced(pid, &pst, 0);
	  pst = WEXITSTATUS(pst);
	  if(pst){
	    print_if_false(buf, typetag, &name_printed, params);
	    sprintf(verbosestr, " Error:Uncompressing the stored file failed.\n");
	  }
	}

	if(filesize != read_bytes){
	  print_if_false(buf, typetag, &name_printed, params);
	  sprintf(verbosestr,
		DP "File contains %s bytes (%s) than stored version (%s).\n",
			filesize > read_bytes ? "more" : "less",
			size_t_to_intstr(filesize, sizestr1),
			size_t_to_intstr(read_bytes, sizestr2));
	  verbosefunc(verbosestr, params);
	}

	i = params->inputfunc(&c, 1, params);
	if(c != '.' || i < 1){
	  i = formaterr(&type, params, started);
	  have_an_error = 1;
	  goto tryagain;
	}

	started = 1;
	have_an_error = 0;

	break;

       formaterr_verify_fcont:
	if(compressed){
	  if(inpp[1] >= 0)
	    close(inpp[1]);
	  close(outpp[0]);
	  if(pid >= 0){
	    kill(pid, SIGTERM);
	    waitpid(pid, &pst, 0);
	  }
	}
	close(fd);

	i = formaterr(&type, params, started);
	have_an_error = 1;
	goto tryagain;

	break;


	started = 1;
	have_an_error = 0;

	break;

      default:
	i = formaterr(&type, params, started);
	goto tryagain;
    }
  }

 cleanup:

  if(files){
    for(fileidx = files; *fileidx; fileidx++)
	free(*fileidx);

    free(files);
  }

  return(r);

 eoferr:

  if(files){
    for(fileidx = files; *fileidx; fileidx++)
	free(*fileidx);

    free(files);
  }

  fprintf(errfp, "Error: unexpected end of file.\n");

  return(EOF);
}

Int32
default_input(UChar * buffer, Int32 num, AarParams * params)
{
  Int32	i;

  i = read(params->infd, buffer, num);

  return(i);
}

void
default_verbose(UChar * str, AarParams * params)
{
  if(params->mode == MODE_CONTENTS)
     fprintf(params->outfp, "%s", str);
  else
     fprintf(params->errfp, "%s", str);
}
