Logo Search packages:      
Sourcecode: ras version File versions  Download package

rasmain.c

/*
    ras - Redundant Archive System
    Copyright (C) 1999  Nick Cleaton

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

    Nick Cleaton <nick@cleaton.net>
*/

#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <stddef.h>

#include "common.h"
#include "utils.h"
#include "field.h"
#include "applysum.h"
#include "options.h"
#include "segfname.h"

/****************************************************************************/

static int choosesum_index;

/****************************************************************************/

void restore_missing_segments(int argc, char** argv);
void generate_sums(int argc, char **argv);

int main(int argc, char **argv)
{ 
   int arg_offset;

   arg_offset = get_options(argc, argv);
   choosesum_index = opt_offset;

   init_unlink_list();
   init_field();

   if( opt_create_sums )
      generate_sums(argc-arg_offset, argv+arg_offset);
   else
      restore_missing_segments(argc-arg_offset, argv+arg_offset);

   free_field();
   return 0;
}

/****************************************************************************
**
**  Restoring any missing segfiles  
*/

int open_sumfile(FILE **f, int *xval, char *filename);
int already_got_xval(struct inblkstream *infiles, size_t ifcount, int xval);

void restore_missing_segments(int argc, char** argv)
{
   int i, first_file_opened, arg, ifcount, ofcount;
   struct outblkstream *outfiles;
   struct inblkstream *infiles;
   FILE *current_file;
   int current_xval;


   if( get_segment_count() == -1 )
   {  /*
       segcount not specified as a command line option, so we must open the 
       first sumfile specified on the command line to find out how many
       segments there are in the archive.
       */  
      if( opt_no_header )
      {  fprintf(stderr,PROGNAME
          ": use the -n option to specify segcount when using the -H option\n");
       exit_because_of_error(INVALID_INPUT);
      }
      if( argc < 1 )
      {  
       fprintf(stderr,PROGNAME ": no sumfiles specified\n");
       exit_because_of_error(INVALID_INPUT);
      }
      open_sumfile( &current_file, &current_xval, argv[0] );
      first_file_opened = 1;
   }
   else
      first_file_opened = 0;


   /*
      Now we know how many segments there are, we have an upper bound on the 
      amount of memory needed for inblkstreams and outblkstreams...
    */  
   infiles = Malloc( get_segment_count() * sizeof(*infiles) );
   outfiles = Malloc( get_segment_count() * sizeof(*outfiles) );


   /*
      Go through the segment files, existing ones become inputs and missing
      ones become outputs.
    */  
   ofcount = 0;
   ifcount = 0;
   for( i=0 ; i<get_segment_count() ; i++ )
   {  
      infiles[ifcount].f = fopen( get_segment_filename(i), "rb" );
      if( infiles[ifcount].f )
      {  /* an existing segment */
         infiles[ifcount].name = get_segment_filename(i);
         infiles[ifcount].x_val = i;
       infiles[ifcount].is_sum = 0;
         ifcount++;
      }
      else
      {  /* a missing segment */
         outfiles[ofcount].name = get_segment_filename(i);
         outfiles[ofcount].f = open_output_file( get_segment_filename(i) );
       outfiles[ofcount].x_val = i;
       outfiles[ofcount].is_sum = 0;
       ofcount++;
       if( opt_verbose )
       {  printf(PROGNAME ": segfile %s missing\n", get_segment_filename(i));
       }
      }
   }


   if( ofcount == 0 )
   {  if( !opt_silent )
      {  printf(PROGNAME ": no segment files missing, nothing to do\n");
      }
      free(infiles);
      free(outfiles);
      return;
   }


   /*
      Now the sumfiles (all inputs)
    */
   arg = 0; 
   while( (arg < argc) && (ifcount < get_segment_count()) )
   {  
      if( arg>0 || !first_file_opened )
         open_sumfile( &current_file, &current_xval, argv[arg] );
      
      if( already_got_xval(infiles, ifcount, current_xval) )
      {  fclose(current_file);
         if( opt_verbose )
       {  printf(PROGNAME ": dropping redundant sumfile %s\n", argv[arg]);
       }
      }
      else
      {  infiles[ifcount].name = argv[arg];
       infiles[ifcount].f = current_file;
       infiles[ifcount].is_sum = 1;
       infiles[ifcount].x_val = current_xval;
       ifcount++;
      }

      arg++;
   }

   if( ifcount < get_segment_count() )
   {  fprintf(stderr,PROGNAME ": too few distinct sumfiles\n");
      exit_because_of_error(NOT_ENOUGH);
   }
   else if( !opt_silent )
   {  printf(PROGNAME ": rebuilding %i of %i segments using %i sums\n",
                                          ofcount, get_segment_count(), argc);
   }


   /*
      Regenerate the missing files
    */
   process_data(ifcount, infiles, ofcount, outfiles, opt_blocksize, 
                                                             !opt_no_footer);


   free(infiles);
   free(outfiles);
}

/*****************************************************************************/

int get_sumID_from_filename(char *filename);

int open_sumfile(FILE **f, int *xval, char *filename)
{
   int segcount, sumID;
   unsigned char headbuf[5];
   
   *f = fopen(filename, "rb");
   if( !(*f) )
   {  fprintf(stderr,PROGNAME ": unable to open sumfile %s for read: %s\n", 
                                                 filename, strerror(errno));
      exit_because_of_error(EXTERNAL_FAILURE);
   }

   if( !opt_no_header )
   {  
      if( fread(headbuf, 1, 5, *f) != 5 )
      {  if( ferror(*f) )
       {  fprintf(stderr,PROGNAME ": read error on sumfile %s: %s\n",
                                        filename, strerror(errno));
          exit_because_of_error(EXTERNAL_FAILURE);
       }
       else
       {  fprintf(stderr,PROGNAME
                              ": unexpected EOF in sumfile %s\n", filename);
          exit_because_of_error(INVALID_INPUT);
       }
      }

      if(   headbuf[0] != 'S' || headbuf[1] != 'U'
       || (headbuf[2] != 'M' && headbuf[2] != '8')     )
      {  fprintf(stderr,PROGNAME ": %s isn't a sumfile\n", filename);
       exit_because_of_error(INVALID_INPUT);
      }

      if( headbuf[2] == 'M' )
      {  fprintf(stderr,
          PROGNAME ": This is ras version " PROGVERSION 
                   ". Sumfile %s was generated by ras 0.90,\n"
          PROGNAME
                ": I can't use it. Version 0.90 is still available, "
              "mail nick@cleaton.net\n"
          PROGNAME ": if you have trouble getting hold of it.\n", filename
        );
       exit_because_of_error(INVALID_INPUT);
      }

      segcount = (int) (headbuf[3]);
      register_segment_count( segcount, "sumfile header" );

      sumID = (int) (headbuf[4]);
   }
   else
      sumID = get_sumID_from_filename(filename);

   if( sumID<0 || sumID > (255-get_segment_count()) )
   {  fprintf(stderr,PROGNAME ": invalid ID of %i in sumfile %s\n",
                                                            sumID, filename);
      exit_because_of_error(INVALID_INPUT);
   }
   *xval = sumID + get_segment_count();

   return get_segment_count();
}
 
/*****************************************************************************/

int already_got_xval(struct inblkstream *infiles, size_t ifcount, int xval)
{
   int i;

   for( i=0 ; i<ifcount ; i++ )
   {  if( infiles[i].x_val == xval )
         return 1;
   }

   return 0;
}

/*****************************************************************************/

int get_sumID_from_filename(char *filename)
{
   char *p;

   p = filename;
   while( !isdigit(*p) )
   {  if( !*p )
      {  fprintf(stderr,PROGNAME ": unable to infer sumfile ID from "
                                 "filename %s\n", filename);
         exit_because_of_error(INVALID_INPUT);
      }
      p++;
   }

   return atoi(p);
}



/****************************************************************************
**
**  Generating sumfiles from segfiles
*/

void init_sum_outfile(char *spec, struct outblkstream *of);

void generate_sums(int argc, char **argv)
{
   int segs, i;
   struct inblkstream infiles[MAX_SEGMENT_COUNT];
   struct outblkstream *outfiles;

   if( argc < 1 )
   {  fprintf(stderr, PROGNAME ": too few sumfiles on command line\n");
      exit_because_of_error(INVALID_INPUT);
   }

   outfiles = Malloc( argc * sizeof(*outfiles) );

   /*
    Open all the input files and initialise the inblkstreams for process_data.
    If the number of segments has not been specified in an option, we must
    must work it out by seeing how many of the segment files exist.
    */

   if( get_segment_count() == -1 )
      segs = MAX_SEGMENT_COUNT;
   else
      segs = get_segment_count();
      
   for( i=0 ; i<segs ; i++ )
   {  
      infiles[i].f = fopen( get_segment_filename(i), "rb" );
      if( infiles[i].f )
      {  infiles[i].name = get_segment_filename(i);
         infiles[i].is_sum = 0;
       infiles[i].x_val = i;
      }
      else
      {  if( get_segment_count() == -1 )
         {  register_segment_count(i, "number of seg files found");
          break;
       }
       else
       {  fprintf(stderr,PROGNAME ": can't open seg file %s for read: %s\n",
                                  get_segment_filename(i), strerror(errno));
          exit_because_of_error(INVALID_INPUT);
       }
      }
   }

   if( get_segment_count() == -1 )
   {  /* We fell out the bottom of the for loop */
      register_segment_count(MAX_SEGMENT_COUNT, "number of segfiles found");
   }
    
   /*
    Now we know how many segments there are we can decide what sums to
    generate and write the headers to the output sumfiles.
   */
   for( i=0 ; i<argc ; i++ )
      init_sum_outfile( argv[i], outfiles + i );
      

   if( !opt_silent )
   {  printf(PROGNAME ": generating %i sumfiles of %i segments\n", argc,
                                                      get_segment_count());
   }
      
   /*
    And finally ....
    */
   process_data(get_segment_count(), infiles, argc, outfiles,
                                            opt_blocksize, !opt_no_footer);

   free( outfiles );
}

/**************************************************************************/

void init_sum_outfile(char *spec, struct outblkstream *of)
{
   char *filename, *s, *heapstr;
   uchar head[5];
   int coloncount, sumID;

   heapstr = Strdup(spec);  /* wish to modify it in situ */
   s = heapstr;

   /*
      Determine the output filename and the sum to be generated from
      the command line argument
    */  
   coloncount = countchar(s, ':'); 
   switch ( coloncount )
   {  case 0: /* filename only specified */
         filename = s;
       sumID = choosesum_index++;
       break;
      case 1: /* filename + x value specified */
         filename = popfirstword( &s, ':' );
       sumID = atoi(s);
       choosesum_index++;
         break;
      default: 
         fprintf(stderr,PROGNAME ": invalid sumspec %s\n", spec);
       exit_because_of_error(INVALID_INPUT);
       filename = NULL;  /* to silence a compiler warning */
       sumID = 0;
   }

   if( sumID<0 || sumID > (255-get_segment_count()) )
   {  fprintf(stderr,PROGNAME ": invalid ID of %i for sumfile %s\n",
                                                            sumID, filename);
      exit_because_of_error(INVALID_INPUT);
   }


   /*
      initialise the outblkstream
    */   
   of->is_sum = 1;
   of->f = open_output_file( nofree(Strdup(filename)) );
   of->name = nofree(Strdup(filename));
   of->x_val = sumID + get_segment_count();
             
   if( !opt_no_header )        
   {  /*
       Write the header to the sumfile
       */
      head[0] = 'S'; head[1] = 'U'; head[2] = '8';
      head[3] = fit_int_in_uchar( get_segment_count() );
      head[4] = fit_int_in_uchar( sumID );
      if( fwrite(head, 1, 5, of->f) != 5 )
      {  perror(PROGNAME ": writing header to sum file");
       exit_because_of_error(EXTERNAL_FAILURE);
      }
   }

   if( opt_verbose )
   {  printf(PROGNAME ": writing sumfile %s, using ID %i\n", filename,
                                                                  sumID);
   }

   free( heapstr );
}

/**************************************************************************/


Generated by  Doxygen 1.6.0   Back to index