Пример #1
0
int main(int argc, char **argv){

//  Bytef *source,*sourcecheck,*dest;
//  int sourceLen, destLen;
//  int returncode;

  char *arg;

  char *filebase;
  int filelen;
  char smvfile[1024];
  char smzlogfile[1024];
  char smvfilebase[1024];
  char *ext;
  char inifile[1024];
  char inifilebase[1024];
  char *prog;
  int i;
  int endian_fds;
  int endian_info;
  int redirect=0;

  set_stdout(stdout);
  initMALLOC();
  GLOBdoit_lighting=0;
  GLOBdoit_smoke3d=1;
  GLOBdoit_boundary=1;
  GLOBdoit_slice=1;
  GLOBdoit_volslice=1;
#ifdef pp_PLOT3D
  GLOBdoit_plot3d=1;
#else
  GLOBdoit_plot3d=0;
#endif
#ifdef pp_PART2
  GLOBdoit_particle=0;
#endif

#ifdef pp_KDTEST
  test_kd();
  exit(0);
#endif
  strcpy(GLOBpp,"%");
  strcpy(GLOBx,"X");
  GLOBfirst_initsphere=1;
  GLOBfirst_slice=1;
  GLOBfirst_patch=1;
  GLOBfirst_plot3d=1;
  GLOBfirst_part2iso=1;
  GLOBfirst_part2iso_smvopen=1;
#ifdef pp_THREAD
  mt_nthreads=2;
#endif
  GLOBframeskip=-1;
  GLOBno_chop=0;
  GLOBautozip=0;
  GLOBmake_demo=0;
  GLOBendf=0;
  GLOBsyst=0;
  GLOBendianfile=NULL;
  GLOBdestdir=NULL;
  GLOBsourcedir=NULL;
  endianswitch=-1;
  GLOBoverwrite_b=0;
  GLOBoverwrite_s=0;
  GLOBget_bounds=0;
  GLOBget_slice_bounds=0;
  GLOBget_plot3d_bounds=0;
  GLOBget_boundary_bounds=0;
#ifdef pp_PART
  GLOBget_part_bounds=0;
  GLOBpartfile2iso=0;
#endif
  GLOBoverwrite_slice=0;
  GLOBoverwrite_volslice=0;
  GLOBoverwrite_plot3d=0;
  endian_info=0;
  GLOBcleanfiles=0;
  GLOBsmoke3dzipstep=1;
  GLOBboundzipstep=1;
  GLOBslicezipstep=1;
  GLOBfilesremoved=0;

  npatchinfo=0;
  nsmoke3dinfo=0;
#ifdef pp_PART
  npartinfo=0;
  npartclassinfo=0;
  partinfo=NULL;
  partclassinfo=NULL;
  maxpart5propinfo=0;
  npart5propinfo=0;
#endif
  nsliceinfo=0;
  sliceinfo=NULL;
  nmeshes=0;

  patchinfo=NULL;
  smoke3dinfo=NULL;

  prog=argv[0];
  filebase=NULL;
  if(argc==1){
    version();
    return 1;
  }

  for(i=1;i<argc;i++){
    int lenarg;
    int lenarg2;
    char *arg2;

    arg=argv[i];
    lenarg=strlen(arg);
    if(arg[0]=='-'&&lenarg>1){
      switch(arg[1]){
      case 'a':
        GLOBautozip=1;
        break;
      case 'b':
        if(strcmp(arg,"-bounds")==0){
          GLOBget_bounds=1;
          GLOBget_slice_bounds=1;
#ifdef pp_PLOT3D
          GLOBget_plot3d_bounds=1;
#endif
          GLOBget_boundary_bounds=1;
#ifdef pp_PART
          GLOBget_part_bounds=1;
#endif
        }
        else if(strcmp(arg,"-bb")==0){
          GLOBget_boundary_bounds=1;
        }
        else if(strcmp(arg,"-bs")==0){
          GLOBget_slice_bounds=1;
        }
#ifdef pp_PLOT3D
        else if(strcmp(arg,"-bp")==0){
          GLOBget_plot3d_bounds=1;
        }
#endif
#ifdef pp_PART2
        else if(strcmp(arg,"-bP")==0){
          GLOBget_part_bounds=1;
        }
#endif
        else{
          GLOBoverwrite_b=1;
        }
        break;
#ifdef pp_PART2
      case 'y':
        if(strcmp(arg,"-yP")==0){
          GLOBdoit_particle=1;
        }
        break;
#endif
      case 'l':
        GLOBdoit_lighting=1;
        break;
      case 'n':
        if(strcmp(arg,"-n3")==0){
          GLOBdoit_smoke3d=0;
        }
        else if(strcmp(arg,"-nb")==0){
          GLOBdoit_boundary=0;
        }
#ifdef pp_PLOT3D
        else if(strcmp(arg,"-np")==0){
          GLOBdoit_plot3d=0;
        }
#endif
#ifdef pp_PART2
        else if(strcmp(arg,"-nP")==0){
          GLOBdoit_particle=0;
        }
#endif
        else if(strcmp(arg,"-ns")==0){
          GLOBdoit_slice=0;
        }
        else if(strcmp(arg,"-nvs")==0){
          GLOBdoit_volslice=0;
        }
        else if(strcmp(arg,"-no_chop")==0){
          GLOBno_chop=1;
        }
        break;
      case '2':
        GLOBoverwrite_slice=1;
        break;
      case '3':
        GLOBoverwrite_volslice=1;
        GLOBoverwrite_s=1;
        break;
#ifdef  pp_PART2
      case 'P':
        GLOBoverwrite_part=1;
        break;
#endif
      case 'p':
        if(strcmp(arg,"-part2iso")==0){
          GLOBpartfile2iso=1;
        }
#ifdef pp_PLOT3D
        else{
          GLOBoverwrite_plot3d=1;
        }
#endif
        break;
      case 'f':
        GLOBoverwrite_b=1;
        GLOBoverwrite_s=1;
        GLOBoverwrite_slice=1;
        GLOBoverwrite_volslice=1;
#ifdef pp_PLOT3D
        GLOBoverwrite_plot3d=1;
#endif
#ifdef pp_PART2
        GLOBoverwrite_part=1;
#endif
        break;
      case 'c':
        GLOBcleanfiles=1;
        break;
      case 'e':
        endian_info=1;
        break;
      case 'r':
        redirect=1;
        break;
      case 's':
        if(i+1>=argc)break;
        if(lenarg==2){
            lenarg2=strlen(argv[i+1]);
            NewMemory((void **)&GLOBsourcedir,lenarg2+2);
            strcpy(GLOBsourcedir,argv[i+1]);
            if(GLOBsourcedir[lenarg2-1]!=dirseparator[0]){
              strcat(GLOBsourcedir,dirseparator);
            }
            if(getfileinfo(GLOBsourcedir,NULL,NULL)!=0){
              fprintf(stderr,"*** Warning: The source directory specified, %s, does not exist or cannot be accessed\n",GLOBsourcedir);
              return 1;
            }
           i++;
        }
        else if(strcmp(arg,"-skip")==0){
          GLOBframeskip=-1;
          arg2=argv[i+1];
          sscanf(arg2,"%i",&GLOBframeskip);
          if(GLOBframeskip>0){
            GLOBslicezipstep=GLOBframeskip;
            GLOBsmoke3dzipstep=GLOBframeskip;
            GLOBboundzipstep=GLOBframeskip;
          }
          i++;
        }
        break;
      case 'd':
        if(strcmp(arg,"-demo")==0){
          GLOBautozip=1;
          GLOBmake_demo=1;
          break;
        }
        if(i+1<argc){
          lenarg2=strlen(argv[i+1]);
          NewMemory((void **)&GLOBdestdir,lenarg2+2);
          strcpy(GLOBdestdir,argv[i+1]);
          if(GLOBdestdir[lenarg2-1]!=dirseparator[0]){
            strcat(GLOBdestdir,dirseparator);
          }
 //         if(getfileinfo(GLOBdestdir,NULL,NULL)!=0){
 //           fprintf(stderr,"*** Warning: The destination directory %s does not exist or cannot be accessed\n",GLOBdestdir);
 //           return 1;
 //         }
          i++;
        }
        break;
#ifdef pp_THREAD
      case 't':
        mt_compress=1;
        if(i+1<argc){
          arg2=argv[i+1];
          sscanf(arg2,"%i",&mt_nthreads);
          if(mt_nthreads<1)mt_nthreads=1;
          if(mt_nthreads>NTHREADS_MAX)mt_nthreads=NTHREADS_MAX;
          i++;
        }
        break;
#endif
      case 'h':
        usage(prog);
        return 1;
      case 'v':
        version();
        return 1;
      default:
        usage(prog);
        return 1;
      }
    }
    else{
      if(filebase==NULL){
        filebase=argv[i];
      }
    }
  }

#ifdef pp_THREAD
  if(GLOBcleanfiles==1)mt_nthreads=1;
#endif

  // construct smv filename
  
  if(filebase==NULL){
    usage(prog);
    return 1;
  }
#ifdef pp_THREAD
  init_pthread_mutexes();
#endif
  filelen=strlen(filebase);
  if(filelen>4){
    ext=filebase+filelen-4;
    if(strcmp(ext,".smv")==0){
      ext[0]=0;
      filelen=strlen(filebase);
    }
  }
  if(GLOBsourcedir==NULL){
    strcpy(smvfile,filebase);
    strcpy(smzlogfile,filebase);
  }
  else{
    strcpy(smvfile,GLOBsourcedir);
    strcat(smvfile,filebase);
    strcpy(smzlogfile,GLOBsourcedir);
    strcat(smzlogfile,filebase);
  }
  strcpy(smvfilebase,filebase);
  if(GLOBpartfile2iso==1||GLOBcleanfiles==1){
    strcpy(GLOBsmvisofile,smvfile);
    strcat(GLOBsmvisofile,".isosmv");
  }

  strcat(smvfile,".smv");
  if(redirect==1){
    if(GLOBsourcedir==NULL){
      strcpy(smzlogfile,filebase);
    }
    else{
      strcpy(smzlogfile,GLOBsourcedir);
      strcat(smzlogfile,filebase);
    }
    strcat(smzlogfile,".smzlog");
    SMZLOG_STREAM=fopen(smzlogfile,"w");
    if(SMZLOG_STREAM!=NULL){
      set_stdout(SMZLOG_STREAM);
    }
  }
  
  // construct ini file name

  strcpy(inifile,smvfile);
  inifile[strlen(inifile)-4]=0;
  strcat(inifile,".ini");
  strcpy(inifilebase,filebase);
  strcat(inifilebase,".ini");

  strcpy(GLOBendianfilebase,"");

  // make sure smv file name exists

  if(getfileinfo(smvfile,NULL,NULL)!=0){
    fprintf(stderr,"*** Error: The file %s does not exist\n",smvfile);
    return 1;
  }

  // make sure smv file can be opened

  if(readsmv(smvfile)!=0)return 1;

#ifdef pp_PLOT3D
  if(nplot3dinfo>0){
    plot3dinfo[0].dup=0;
    for(i=1;i<nplot3dinfo;i++){
      plot3d *plot3di; 

      plot3di = plot3dinfo + i;

      plot3di->dup=0;
      plot3ddup(plot3di,i);
    }
  }
#endif
  if(npatchinfo>0){
    patchinfo->dup=0;
    for(i=1;i<npatchinfo;i++){
      patch *patchi; 

      patchi = patchinfo + i;

      patchi->dup=0;
      patchdup(patchi,i);
    }
  }
  if(nsliceinfo>0){
    sliceinfo[0].dup=0;
    for(i=1;i<nsliceinfo;i++){
      slice *slicei; 

      slicei = sliceinfo + i;

      slicei->dup=0;
      slicedup(slicei,i);
    }
  }

  if(getendian()==1){
      PRINTF("Smokezip running on a big endian computer.\n");
  }
  else{
      PRINTF("Smokezip running on a little endian computer.\n");
  }
  if(GLOBendf==0&&GLOBsyst==0){
    fprintf(stderr,"Warning: casename.end file is missing.  Endianness of\n");
    fprintf(stderr,"         FDS boundary file data is unknown.\n");
    if(getendian()==1){
      fprintf(stderr,"         Assuming FDS boundary data is big endian - \n");
    }
    if(getendian()==0){
      fprintf(stderr,"         Assuming FDS boundary data is little endian - \n");
    }
    fprintf(stderr,"         or equivalently assuming FDS and Smokezip are\n");
    fprintf(stderr,"         being run on the same type of computer\n");
    endianswitch=0;
  }
  else{
    endian_fds=getendian()+endianswitch;
    if(endian_fds==2)endian_fds=0;
    if(endian_fds==1){
      PRINTF("FDS was run on a big endian computer. \n\n");
    }
    else{
      PRINTF("FDS was run on a little endian computer.\n\n");
    }
  }
  if(endian_info==1)return 0;

  readini(inifile);

#ifdef pp_THREAD
  mt_compress_all();
#else
  compress_all(NULL);
#endif

  if(GLOBcleanfiles==0&&GLOBdestdir!=NULL){
    PRINTF("Copying .smv, .ini and .end files to %s directory\n",GLOBdestdir);
    filecopy(GLOBdestdir,smvfile,smvfilebase);
    filecopy(GLOBdestdir,inifile,inifilebase);
    filecopy(GLOBdestdir,GLOBendianfile,GLOBendianfilebase);
  }
  if(GLOBcleanfiles==1&&GLOBfilesremoved==0){
    PRINTF("No compressed files were removed\n");
  }
  if(GLOBmake_demo==1){
    makesvd(GLOBdestdir,smvfile);
  }
  return 0;
}
Пример #2
0
int main(int argc, char *argv[])
{
	bool lrzcat = false, compat = false, recurse = false;
	struct timeval start_time, end_time;
	struct sigaction handler;
	double seconds,total_time; // for timers
	int c, i;
	int hours,minutes;
	extern int optind;
	char *eptr, *av; /* for environment */

        control = &base_control;

	initialise_control(control);

	av = basename(argv[0]);
	if (!strcmp(av, "lrunzip"))
		control->flags |= FLAG_DECOMPRESS;
	else if (!strcmp(av, "lrzcat")) {
		control->flags |= FLAG_DECOMPRESS | FLAG_STDOUT;
		lrzcat = true;
	} else if (!strcmp(av, "lrz")) {
		/* Called in gzip compatible command line mode */
		control->flags &= ~FLAG_SHOW_PROGRESS;
		control->nice_val = 0;
		control->flags &= ~FLAG_KEEP_FILES;
		compat = true;
		long_options[1].name = "stdout";
		long_options[11].name = "keep";
	}

	/* generate crc table */
	CrcGenerateTable();

	/* Get Preloaded Defaults from lrzip.conf
	 * Look in ., $HOME/.lrzip/, /etc/lrzip.
	 * If LRZIP=NOCONFIG is set, then ignore config
	 */
	eptr = getenv("LRZIP");
	if (eptr == NULL)
		read_config(control);
	else if (!strstr(eptr,"NOCONFIG"))
		read_config(control);

	while ((c = getopt_long(argc, argv, compat ? coptions : loptions, long_options, &i)) != -1) {
		switch (c) {
		case 'b':
			if (control->flags & FLAG_NOT_LZMA)
				failure("Can only use one of -l, -b, -g, -z or -n\n");
			control->flags |= FLAG_BZIP2_COMPRESS;
			break;
		case 'c':
			if (compat) {
				control->flags |= FLAG_KEEP_FILES;
				set_stdout(control);
				break;
			}
		case 'C':
			control->flags |= FLAG_CHECK;
			control->flags |= FLAG_HASH;
			break;
		case 'd':
			control->flags |= FLAG_DECOMPRESS;
			break;
		case 'D':
			control->flags &= ~FLAG_KEEP_FILES;
			break;
		case 'e':
			control->flags |= FLAG_ENCRYPT;
			break;
		case 'f':
			control->flags |= FLAG_FORCE_REPLACE;
			break;
		case 'g':
			if (control->flags & FLAG_NOT_LZMA)
				failure("Can only use one of -l, -b, -g, -z or -n\n");
			control->flags |= FLAG_ZLIB_COMPRESS;
			break;
		case 'h':
		case '?':
			usage(compat);
			return -1;
		case 'H':
			control->flags |= FLAG_HASH;
			break;
		case 'i':
			control->flags |= FLAG_INFO;
			break;
		case 'k':
			if (compat) {
				control->flags |= FLAG_KEEP_FILES;
				break;
			}
		case 'K':
			control->flags |= FLAG_KEEP_BROKEN;
			break;
		case 'l':
			if (control->flags & FLAG_NOT_LZMA)
				failure("Can only use one of -l, -b, -g, -z or -n\n");
			control->flags |= FLAG_LZO_COMPRESS;
			break;
		case 'L':
			if (compat) {
				license();
				exit(0);
			}
			control->compression_level = atoi(optarg);
			if (control->compression_level < 1 || control->compression_level > 9)
				failure("Invalid compression level (must be 1-9)\n");
			break;
		case 'm':
			control->ramsize = atol(optarg) * 1024 * 1024 * 100;
			break;
		case 'n':
			if (control->flags & FLAG_NOT_LZMA)
				failure("Can only use one of -l, -b, -g, -z or -n\n");
			control->flags |= FLAG_NO_COMPRESS;
			break;
		case 'N':
			control->nice_val = atoi(optarg);
			if (control->nice_val < -20 || control->nice_val > 19)
				failure("Invalid nice value (must be -20..19)\n");
			break;
		case 'o':
			if (control->outdir)
				failure("Cannot have -o and -O together\n");
			if (unlikely(STDOUT))
				failure("Cannot specify an output filename when outputting to stdout\n");
			control->outname = optarg;
			control->suffix = "";
			break;
		case 'O':
			if (control->outname)	/* can't mix -o and -O */
				failure("Cannot have options -o and -O together\n");
			if (unlikely(STDOUT))
				failure("Cannot specify an output directory when outputting to stdout\n");
			control->outdir = malloc(strlen(optarg) + 2);
			if (control->outdir == NULL)
				fatal("Failed to allocate for outdir\n");
			strcpy(control->outdir,optarg);
			if (strcmp(optarg+strlen(optarg) - 1, "/")) 	/* need a trailing slash */
				strcat(control->outdir, "/");
			break;
		case 'p':
			control->threads = atoi(optarg);
			if (control->threads < 1)
				failure("Must have at least one thread\n");
			break;
		case 'P':
			control->flags |= FLAG_SHOW_PROGRESS;
			break;
		case 'q':
			control->flags &= ~FLAG_SHOW_PROGRESS;
			break;
		case 'r':
			recurse = true;
			break;
		case 'S':
			if (control->outname)
				failure("Specified output filename already, can't specify an extension.\n");
			if (unlikely(STDOUT))
				failure("Cannot specify a filename suffix when outputting to stdout\n");
			control->suffix = optarg;
			break;
		case 't':
			if (control->outname)
				failure("Cannot specify an output file name when just testing.\n");
			if (compat)
				control->flags |= FLAG_KEEP_FILES;
			if (!KEEP_FILES)
				failure("Doubt that you want to delete a file when just testing.\n");
			control->flags |= FLAG_TEST_ONLY;
			break;
		case 'T':
			control->flags &= ~FLAG_THRESHOLD;
			break;
		case 'U':
			control->flags |= FLAG_UNLIMITED;
			break;
		case 'v':
			/* set verbosity flag */
			if (!(control->flags & FLAG_SHOW_PROGRESS))
				control->flags |= FLAG_SHOW_PROGRESS;
			else if (!(control->flags & FLAG_VERBOSITY) && !(control->flags & FLAG_VERBOSITY_MAX))
				control->flags |= FLAG_VERBOSITY;
			else if ((control->flags & FLAG_VERBOSITY)) {
				control->flags &= ~FLAG_VERBOSITY;
				control->flags |= FLAG_VERBOSITY_MAX;
			}
			break;
		case 'V':
			print_output("lrzip version %s\n", PACKAGE_VERSION);
			exit(0);
			break;
		case 'w':
			control->window = atol(optarg);
			break;
		case 'z':
			if (control->flags & FLAG_NOT_LZMA)
				failure("Can only use one of -l, -b, -g, -z or -n\n");
			control->flags |= FLAG_ZPAQ_COMPRESS;
			break;
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			control->compression_level = c - '0';
			break;
		}
	}

	argc -= optind;
	argv += optind;

	if (control->outname) {
		if (argc > 1)
			failure("Cannot specify output filename with more than 1 file\n");
		if (recurse)
			failure("Cannot specify output filename with recursive\n");
	}

	if (VERBOSE && !SHOW_PROGRESS) {
		print_err("Cannot have -v and -q options. -v wins.\n");
		control->flags |= FLAG_SHOW_PROGRESS;
	}

	if (UNLIMITED && control->window) {
		print_err("If -U used, cannot specify a window size with -w.\n");
		control->window = 0;
	}

	if (argc < 1)
		control->flags |= FLAG_STDIN;

	if (UNLIMITED && STDIN) {
		print_err("Cannot have -U and stdin, unlimited mode disabled.\n");
		control->flags &= ~FLAG_UNLIMITED;
	}

	setup_overhead(control);

	/* Set the main nice value to half that of the backend threads since
	 * the rzip stage is usually the rate limiting step */
	if (control->nice_val > 0 && !NO_COMPRESS) {
		if (unlikely(setpriority(PRIO_PROCESS, 0, control->nice_val / 2) == -1))
			print_err("Warning, unable to set nice value\n");
	} else {
		if (unlikely(setpriority(PRIO_PROCESS, 0, control->nice_val) == -1))
			print_err("Warning, unable to set nice value\n");
	}

	/* One extra iteration for the case of no parameters means we will default to stdin/out */
	for (i = 0; i <= argc; i++) {
		char *dirlist = NULL, *infile = NULL;
		int direntries = 0, curentry = 0;

		if (i < argc)
			infile = argv[i];
		else if (!(i == 0 && STDIN))
			break;
		if (infile) {
			if ((strcmp(infile, "-") == 0))
				control->flags |= FLAG_STDIN;
			else {
				bool isdir = false;
				struct stat istat;

				if (unlikely(stat(infile, &istat)))
					failure("Failed to stat %s\n", infile);
				isdir = S_ISDIR(istat.st_mode);
				if (!recurse && (isdir || !S_ISREG(istat.st_mode))) {
					failure("lrzip only works directly on regular FILES.\n"
					"Use -r recursive, lrztar or pipe through tar for compressing directories.\n");
				}
				if (recurse && !isdir)
					failure("%s not a directory, -r recursive needs a directory\n", infile);
			}
		}

		if (recurse) {
			if (unlikely(STDIN || STDOUT))
				failure("Cannot use -r recursive with STDIO\n");
			recurse_dirlist(infile, &dirlist, &direntries);
		}

		if (INFO && STDIN)
			failure("Will not get file info from STDIN\n");
recursion:
		if (recurse) {
			if (curentry >= direntries) {
				infile = NULL;
				continue;
			}
			infile = dirlist + MAX_PATH_LEN * curentry++;
		}
		control->infile = infile;

		/* If no output filename is specified, and we're using
		 * stdin, use stdout */
		if ((control->outname && (strcmp(control->outname, "-") == 0)) ||
		    (!control->outname && STDIN) || lrzcat)
				set_stdout(control);

		if (lrzcat) {
			control->msgout = stderr;
			control->outFILE = stdout;
			register_outputfile(control, control->msgout);
		}

		if (!STDOUT) {
			control->msgout = stdout;
			register_outputfile(control, control->msgout);
		}

		if (STDIN)
			control->inFILE = stdin;
		/* Implement signal handler only once flags are set */
		sigemptyset(&handler.sa_mask);
		handler.sa_flags = 0;
		handler.sa_handler = &sighandler;
		sigaction(SIGTERM, &handler, 0);
		sigaction(SIGINT, &handler, 0);

		if (!FORCE_REPLACE) {
			if (STDIN && isatty(fileno((FILE *)stdin))) {
				print_err("Will not read stdin from a terminal. Use -f to override.\n");
				usage(compat);
				exit (1);
			}
			if (!TEST_ONLY && STDOUT && isatty(fileno((FILE *)stdout)) && !compat) {
				print_err("Will not write stdout to a terminal. Use -f to override.\n");
				usage(compat);
				exit (1);
			}
		}

		if (CHECK_FILE) {
			if (!DECOMPRESS) {
				print_err("Can only check file written on decompression.\n");
				control->flags &= ~FLAG_CHECK;
			} else if (STDOUT) {
				print_err("Can't check file written when writing to stdout. Checking disabled.\n");
				control->flags &= ~FLAG_CHECK;
			}
		}

		setup_ram(control);
		show_summary();

		gettimeofday(&start_time, NULL);

		if (unlikely(STDIN && ENCRYPT))
			failure("Unable to work from STDIN while reading password\n");

		memcpy(&local_control, &base_control, sizeof(rzip_control));
		if (DECOMPRESS || TEST_ONLY)
			decompress_file(&local_control);
		else if (INFO)
			get_fileinfo(&local_control);
		else
			compress_file(&local_control);

		/* compute total time */
		gettimeofday(&end_time, NULL);
		total_time = (end_time.tv_sec + (double)end_time.tv_usec / 1000000) -
			      (start_time.tv_sec + (double)start_time.tv_usec / 1000000);
		hours = (int)total_time / 3600;
		minutes = (int)(total_time / 60) % 60;
		seconds = total_time - hours * 3600 - minutes * 60;
		if (!INFO)
			print_progress("Total time: %02d:%02d:%05.2f\n", hours, minutes, seconds);
		if (recurse)
			goto recursion;
	}

	return 0;
}