#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include "mtd.h"

void err(char *dir,char *type,FILE *f,MTDFILE *f2) {
  long ft = ftell(f);

  printf("Error %s %s: %m\n",dir,type);
  printf("Offset %X (%d)\n",ft,ft);
  printf("Block %d, sector %d, byte %d\n",
	 MTDblock(f2,ft),MTDsector(f2,ft),MTDbyte(f2,ft));
}

int main(int argc,char *argv[]) {
  MTDFILE *f;
  FILE *f2;
  char tmp[256],*buf;
  mtd_info_t inf;
  int i,block,len=0,len0;
  struct stat stat;

  if (argc == 4) { // copy TO MTD
    sprintf(tmp,"/dev/mtd/%d",atoi(argv[2]));
    f = MTDopen(tmp);
    if (f == NULL) {
      printf("MTDopen(%s) failed: %m\n",tmp);
      return 0;
    }
    block = atoi(argv[3]);
    if (!MTDseek(f,block,0,0)) {
      printf("Can't find starting MTD block %d: %m\n",block);
      return 0;
    }
    f2 = fopen(argv[1],"r");
    if (!f2) {
      printf("Can't open source file %s: %m\n",argv[1]);
      return 0;
    }
  } else if (argc == 5) { // copy FROM MTD
    sprintf(tmp,"/dev/mtd/%d",atoi(argv[1]));
    f = MTDopen(tmp);
    if (f == NULL) {
      printf("MTDopen(%s) failed: %m\n",tmp);
      return 0;
    }
    block = atoi(argv[2]);
    if (!MTDseek(f,block,0,0)) {
      printf("Can't find starting MTD block %d: %m\n",block);
      return 0;
    }
    len = atoi(argv[3]);
    f2 = fopen(argv[4],"w");
    if (!f2) {
      printf("Can't open destination file %s: %m\n",argv[1]);
      return 0;
    }
  } else {
    printf("Usage:\n");
    printf("\tmtdcopy part# block# bytes dest\n");
    printf("\tmtdcopy src part# block#\n");
    return 0;
  }

  buf = malloc(f->info.erasesize);
  if (len == 0) { // copying from file to MTD
    fstat(fileno(f2),&stat);
    len = stat.st_size;
    if (len > f->info.size) {
      printf("File size is %d, destination can only hold %d (aborting)\n",
	     len,f->info.size);
      return 1;
    }
    if (len == 0) {
      while (!feof(f2)) {
	for (i=0;i<f->info.erasesize;i++) {
	  buf[i] = 0xFF;
	}
	if (fread(buf,1,f->info.erasesize,f2) > 0) {
	  if (!MTDwrite(f,buf,f->info.erasesize)) {
	    err("writing","MTD",f->f,f);
	    return 0;
	  }
	} else {
	  break;
	}
      }
    } else while (len > 0) {
      len0 = len > f->info.erasesize ? f->info.erasesize : len;
      if (fread(buf,len0,1,f2) != 1) {
	err("reading","file",f2,f);
	return 0;
      }
      if (!MTDwrite(f,buf,len0)) {
	err("writing","MTD",f->f,f);
	return 0;
      }
      len -= len0;
    }
  } else { // copying from MTD to file
    while (len > 0) {
      len0 = len > f->info.erasesize ? f->info.erasesize : len;
      if (!MTDread(f,buf,len0)) {
	err("reading","MTD",f->f,f);
	return 0;
      }
      if (fwrite(buf,len0,1,f2) != 1) {
	err("writing","file",f2,f);
	return 0;
      }
      len -= len0;
    }
  }

  /*
  printf("%d bytes (+%d) per sector\n",f->info.oobblock,f->info.oobsize);
  i = sciformat(f->info.erasesize,&pwr,&fract);
  printf("%d sectors (%d.%d%cB) per block\n",
	 f->info.erasesize/f->info.oobblock,i,fract,PWR(pwr));
  i = sciformat(f->info.size,&pwr,&fract);
  printf("%d blocks (%d.%d%cB) total\n",f->info.size/f->info.erasesize,
	 i,fract,PWR(pwr));

  for (i=0;i<f->info.erasesize/f->info.oobblock;i++) {
    MTDreadOOB(f,0,i,tmp);
    dump(tmp,f->info.oobsize,i);
  }
  */

}
