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

afcat.cpp

/*
 * afcat.cpp:
 *
 * cat the contents of an AFF file...
 */

/*
 * Copyright (c) 2005, 2006
 *    Simson L. Garfinkel and Basis Technology, Inc. 
 *      All rights reserved.
 *
 * This code is derrived from software contributed by
 * Simson L. Garfinkel
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by Simson L. Garfinkel
 *    and Basis Technology Corp.
 * 4. Neither the name of Simson Garfinkel, Basis Technology, or other
 *    contributors to this program may be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY,
 * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.  
 */


#include "afflib.h"
#include "afflib_i.h"

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <zlib.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <assert.h>

#include <algorithm>
#include <cstdlib>
#include <vector>
#include <string>
using namespace std;

vector <int64> pages;

char *progname = "afcat";
int  opt_info     = 0;
char *opt_segname=0;
int64  opt_pagenum = -1;
int opt_quiet = 1;
int opt_list= 0 ;
int opt_list_long = 0;
int opt_debug = 0;
int64 opt_sector = -1;
int opt_badflag = 0;

#define xstr(s) str(s)
#define str(s) #s



void usage()
{
    printf("afcat version %s\n",xstr(AFFLIB_VERSION));
    printf("usage: afcat [options] infile [... more infiles]\n");
    printf("options:\n");
    printf("    -s name --- Just output segment name\n");
    printf("    -p ###  --- just output data page number ###\n");
    printf("    -S ###  --- Just output data sector ### (assumes 512-byte sectors). Sector #0 is first\n");
    printf("    -q      --- quiet; don't print to STDERR if a page is skipped\n");
    printf("    -n      --- noisy; tell when pages are skipped.\n");
    printf("    -l      --- List all of the segment names\n");
    printf("    -L      --- List segment names, lengths, and args\n");
    printf("    -d      --- debug. Print the page numbers to stderr as data goes to stdout\n");
    printf("    -b      --- Output BADFALG for bad blocks (default is NULLs)\n");
    printf("    -v      --- Just print the version number and exit.\n");
    exit(0);
}

int compar(const void *a_,const void *b_)
{
    int64 a = *(int *)a_;
    int64 b = *(int *)b_;
    if(a<b) return -1;
    if(a>b) return 1;
    return 0;
}

struct afm_private {
    AFFILE *aff;              // the AFFILE we use for the actual metadata
    AFFILE *sr;                     // the AFFILE we use for the splitraw
    int sr_initialized;             // has the split-raw been setup from AFM?
};

int output_page(AFFILE *af,FILE *outfile,int64 pagenum)
{
    unsigned char *buf = (unsigned char *)malloc(af->image_pagesize);
    if(buf==0){
      err(1,"malloc(%d) failed",(int)af->image_pagesize);
    }
    uint64 offset = (uint64)pagenum * af->image_pagesize; // go to that location


    af_seek(af,offset,SEEK_SET);


    int bytes = af_read(af,buf,af->image_pagesize); // read what we can

    if(bytes<0){
      if(opt_debug) fprintf(stderr,"afcat: cannot read page %"I64d"\n",pagenum);
      return -1;
    }

    if(opt_debug){
      fprintf(stderr,"afcat: page:%"I64d" bytes: %d offset:%"I64d"\n",
            pagenum, bytes,offset);
    }

    /* Check each sector to see if it is badflag or not.
     * If it is and if opt_badflag is not set, make it all NULs.
     */
    for(unsigned char *cc=buf;cc<buf+bytes;cc+=af->image_sectorsize){
      if(af_is_badblock(af,cc) && opt_badflag==0){
          memset(cc,0,af->image_sectorsize);
      }
    }

    fwrite(buf,1,bytes,outfile);    // send to the output
    free(buf);
    return bytes;
}


int afcat(AFFILE *af)
{
    int64 total_bytes_written = 0;

    /* Read all of the pages from beginning to end and capture
     * all the segment numbers...
     */

    if(opt_segname){
      /* First figure out how big the segment is */
      size_t datalen = 0;
      if(af_get_seg(af,opt_segname,0,0,&datalen)){
          fprintf(stderr,"%s: segment '%s' does not exist\n",
                af_filename(af),opt_segname);
          return -1;
      }
      unsigned char *data = (unsigned char *)malloc(datalen);
      if(data==0) err(1,"malloc");
      if(af_get_seg(af,opt_segname,0,data,&datalen)){
          free(data);
          fprintf(stderr,"%s: could not read segment '%s'\n",
                af_filename(af),opt_segname);
          return -1;
      }
      fwrite(data,1,datalen,stdout);
      free(data);
      return 0;
    }

    if(opt_pagenum != -1){          // just write a particular page?
      int r = output_page(af,stdout,opt_pagenum);
      return r>=0 ? 0 : -1;
    }

    if(opt_sector>=0){
      unsigned char *buf = (unsigned char *)malloc(af->image_sectorsize);
      af_seek(af,(uint64)opt_sector*af->image_sectorsize,SEEK_SET);
      int r = af_read(af,buf,af->image_sectorsize);
      if(r>0){
          fwrite(buf,1,r,stdout);
      }
      free(buf);
      return 0;
    }

    /* Get a list of all the segments. If we are doing a list, just print them.
     * If we are not doing a list, capture the data pages and put their numbers
     * into an array.
     */
    af_rewind_seg(af);              // start at the beginning
    char segname[AF_MAX_NAME_LEN];
    unsigned long arg;
    size_t datalen = 0;
    memset(segname,0,sizeof(segname));
    
    while(af_get_next_seg(af,segname,sizeof(segname),&arg,0,&datalen)==0){
      if(segname[0]==0) continue;   // ignore sector
      if(opt_list){
          printf("%s",segname);
          if(opt_list_long){
            printf("\t%lu\t%d",arg,(int)datalen);
          }
          putchar('\n');
      }
      else {
          int64 pagenum = af_segname_page_number(segname);
          if(pagenum>=0) pages.push_back(pagenum);
      }
      datalen = 0;                  // allow to get the next one
    }
    if(opt_list) return 0;          // that's all that was wanted.


    sort(pages.begin(),pages.end());
      
    /* Now I have a list of pages; cat each one */
    int next_page = 0;              // starting page number
    int64 imagesize = af_imagesize(af);
    for(vector<int64>::iterator i = pages.begin();
      i != pages.end();
      i++){

      int page = *i;
      if(page != next_page && opt_quiet==0){
          if(page == next_page+1 ){
            fprintf(stderr,"afcat: page %d not in file\n",next_page);
          }
          else{
            fprintf(stderr,"afcat: pages %d through %d not in file\n",
                  next_page,page-1);
          }
      }
      int r = output_page(af,stdout,page);
      if(r<0) return -1;
      total_bytes_written += r;
      next_page = page + 1;   // note what should be next

      if((total_bytes_written > imagesize) &&
         (imagesize>0)){
          err(1,"afcat internal error. bytes written=%"I64d" imagesize=%" I64d,
            total_bytes_written,imagesize);
          return -1;
      }
    }
    return 0;
}


int64 atoi64(const char *buf)
{
    int64 r=0;
    char ch;
    if(sscanf(buf,"%"I64d"%c",&r,&ch)==1) return r;
    fprintf(stderr,"Cannot parse '%s'\n",buf);
    exit(0);
}


int main(int argc,char **argv)
{
    int bflag, ch;

    bflag = 0;
    while ((ch = getopt(argc, argv, "s:S:p:lLh?dqnv")) != -1) {
      switch (ch) {
      case 's':
          opt_segname = optarg;
          break;
      case 'S':
          opt_sector = atoi64(optarg);
          break;
      case 'p':
          opt_pagenum = atoi64(optarg);
          break;
      case 'q':
          opt_quiet = 1;
          break;
      case 'n':
          opt_quiet = 0;
          break;
      case 'l':
          opt_list = 1;
          break;
      case 'L':
          opt_list = 1;
          opt_list_long = 1;
          break;
      case 'b':
          opt_badflag = 1;
          break;
      case 'd':
          opt_debug++;
          break;
      case 'h':
      case '?':
      default:
          usage();
          break;
      case 'v':
          printf("%s version %s\n",progname,xstr(AFFLIB_VERSION));
          exit(0);
      }
    }
    argc -= optind;
    argv += optind;

    if(argc<1){
      usage();
    }

    while(*argv){
      AFFILE *af = af_open(*argv,O_RDONLY,0);
      if(!af) err(1,"afcat(%s)",*argv);
      if(afcat(af)) err(1,"afcat");
      af_close(af);
      argv++;
      argc--;
    }
}

Generated by  Doxygen 1.6.0   Back to index