Page MenuHomePhabricator

affcat.cpp
No OneTemporary

Size
11 KB
Referenced Files
None
Subscribers
None

affcat.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 "affconfig.h"
#include "afflib.h"
#include "afflib_i.h"
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <string>
#ifdef HAVE_CSTRING
#include <cstring>
#endif
using namespace std;
vector <int64_t> pages;
const char *progname = "afcat";
int opt_info = 0;
char *opt_segname=0;
int64_t opt_pagenum = -1;
int opt_quiet = 1;
int opt_list= 0 ;
int opt_list_long = 0;
int opt_debug = 0;
int64_t opt_sector = -1;
int opt_badflag = 0;
vector<string> opt_r;
void usage()
{
printf("afcat version %s\n",PACKAGE_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");
printf(" -r offset:count --- seek to offset and output count characters in each file; may be repeated\n");
exit(0);
}
const char *current_fname = 0;
int64_t current_page = -1;
void sig_info(int arg)
{
fprintf(stderr,"afcat ");
if(current_fname) fprintf(stderr,"%s: ",current_fname);
if(current_page>=0) fprintf(stderr,"[%"PRId64"] ",current_page);
fflush(stderr);
}
int compar(const void *a_,const void *b_)
{
int64_t a = *(int *)a_;
int64_t 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_t pagenum)
{
current_fname = af_filename(af);
current_page = pagenum;
unsigned char *buf = (unsigned char *)malloc(af->image_pagesize);
if(buf==0){
err(1,"malloc(%d) failed",(int)af->image_pagesize);
}
uint64_t offset = (uint64_t)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_badsector(af,cc) && opt_badflag==0){
memset(cc,0,af->image_sectorsize);
}
}
if(opt_debug) fprintf(stderr," outputing %d bytes\n",bytes);
int count = fwrite(buf,1,bytes,outfile); // send to the output
if(count!=bytes) fprintf(stderr,"fwrite(buf,1,%d,outfile) only wrote %d bytes\n",bytes,count);
free(buf);
return bytes;
}
int afcat(AFFILE *af)
{
int64_t total_bytes_written = 0;
/* Read all of the pages from beginning to end and capture
* all the segment numbers...
*/
#ifdef WIN32
_setmode(fileno(stdout),_O_BINARY);
#endif
if(opt_debug) fprintf(stderr,"afcat(%s)\n",af_filename(af));
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;
}
int count = fwrite(data,1,datalen,stdout);
if(count!=(ssize_t)datalen){
fprintf(stderr,"fwrite(buf,1,%zd,outfile) only wrote %d bytes\n",datalen,count);
}
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_t)opt_sector*af->image_sectorsize,SEEK_SET);
int bytes_read = af_read(af,buf,af->image_sectorsize);
if(bytes_read>0){
int bytes_written = fwrite(buf,1,bytes_read,stdout);
if(bytes_read!=bytes_written){
fprintf(stderr,"fwrite(buf,1,%d,outfile) only wrote %d bytes\n",
bytes_read,bytes_written);
}
}
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.
*/
if(opt_debug) fprintf(stderr,"af_rewind_seg()\n");
if(opt_r.size()>0){
unsigned char *buf = (unsigned char *)malloc(af->image_pagesize);
for(vector<string>::const_iterator offset_count=opt_r.begin(); offset_count != opt_r.end(); offset_count++){
string opts = *offset_count;
const char *opt = opts.c_str();
uint64_t offset=0;
int count=0;
if(sscanf(opt,"%"I64u":%d",&offset,&count)!=2){
err(1,"Cannot decode '%s'\n",opt);
}
af_seek(af,offset,SEEK_SET);
int r= af_read(af,buf,count);
if(r>0){
int bytes_written = fwrite(buf,1,r,stdout);
if(bytes_written!=r) {
fprintf(stderr,"fwrite(buf,1,%d,outfile) only wrote %d bytes\n",r,bytes_written);
}
}
}
free(buf);
return 0;
}
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));
int encrypted_segments = 0;
while(af_get_next_seg(af,segname,sizeof(segname),&arg,0,&datalen)==0){
if(opt_debug) fprintf(stderr,"af_get_next_seg found segment %s\n",segname);
if(segname[0]==0) continue; // ignore sector
if(opt_list){
printf("%s",segname);
if(opt_list_long){
printf("\targ:%lu\tlen:%d",arg,(int)datalen);
}
putchar('\n');
}
else {
int64_t pagenum = af_segname_page_number(segname);
if(pagenum>=0) pages.push_back(pagenum);
if(af_is_encrypted_segment(segname)) encrypted_segments++;
}
datalen = 0; // allow to get the next one
}
if(opt_list) return 0; // that's all that was wanted.
sort(pages.begin(),pages.end());
if(pages.size()==0 && encrypted_segments){
fprintf(stderr,"afcat: This file has %d encrypted segments.\n",encrypted_segments);
fprintf(stderr,"afcat: No unencrypted pages could be found.\n");
}
/* Now I have a list of pages; cat each one */
int next_page = 0; // starting page number
int64_t imagesize = af_get_imagesize(af);
for(vector<int64_t>::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
//fprintf(stderr,"bytes written=%qd imagesize=%qd\n",total_bytes_written,imagesize);
if((total_bytes_written > imagesize) && (imagesize>0)){
err(1,"afcat internal error. bytes written=%"I64d" imagesize=%" I64d,
(int64_t)total_bytes_written,
(int64_t)imagesize);
return -1;
}
}
return 0;
}
int64_t atoi64(const char *buf)
{
int64_t 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;
#ifdef SIGINFO
signal(SIGINFO,sig_info);
#endif
bflag = 0;
while ((ch = getopt(argc, argv, "s:S:p:lLh?dqnvr:")) != -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 'r':
opt_r.push_back(optarg);
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,PACKAGE_VERSION);
exit(0);
}
}
argc -= optind;
argv += optind;
if(argc<1){
usage();
}
while(*argv){
AFFILE *af = af_open(*argv,O_RDONLY,0);
if(!af) af_err(1,"afcat(%s)",*argv);
if(afcat(af)) err(1,"afcat");
af_close(af);
argv++;
argc--;
}
}

File Metadata

Mime Type
text/x-c++
Expires
Sat, Nov 22, 12:12 AM (1 d, 7 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1361659
Default Alt Text
affcat.cpp (11 KB)

Event Timeline