#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>

/* Quell- und Zieldatei */
FILE *fp1=NULL, *fp2=NULL;

/* Pointer auf Pufferbereich */
char *buf=NULL;

/* Routine zum "Aufräumen" */
void aus(void)
{
  if (fp1)
    fclose(fp1);

  if (fp2)
    fclose(fp2);

  if (buf)
    free(buf);

  exit(0);
}

int main(int argc, char **argv)
{
 /* String für "system" */
 char del[100];
 /* Puffergröße (Default = 32 KB) */
 unsigned long buffsize = 32768, fsize;
 /* Gelesene und geschriebene Bytes, Laufvariable */
 int size, size1, i;
 /* stat wird benötigt, um Dateigröße zu ermitteln */
 struct stat stdbuf;

 /* Anzahl der Parameter gut ? */
 if (argc < 3) {
   printf("Benutzung : %s <sourcefile> "
          "<destinationfile> [Puffergröße"
          " in KB]\n", argv[0]);
   exit(0);
 }

 /* Dateien öffnen */
 if (!(fp1 = fopen(argv[1], "r"))) {
   printf("File %s konnte nicht geöffnet"
          " werden !\n", argv[1]);
   aus();
 }

 if (!(fp2 = fopen(argv[2], "w"))) {
   printf("File %s konnte nicht geöffnet"
          " werden !\n", argv[2]);
   aus();
 }

 /* Wenn angegeben, Puffergröße neu belegen */
 if (argc == 4)
   buffsize = strtol(argv[3], NULL, 10) * 1024;

 if (!(buf = malloc(buffsize))) {
    printf("Puffergröße %s KB zu groß ! \n", argv[3]);
    aus();
 }

 /* Dateigröße bestimmen */
 stat(argv[1], &stdbuf);
 fsize = stdbuf.st_size;

 /* Solange nicht alles gelesen wurde */
 for (i = 0; i * buffsize < fsize; i++) {
   /* lesen */
   size = fread(buf, 1, buffsize, fp1);

   /* schreiben */
   size1 = fwrite(buf, 1, size, fp2);

   /* Erfolgskontrolle nach dem Schreiben */
   if (size1 != size) {
       /* Bei Fehler : Meldung, Dateien schließen */
       /* und Zieldatei löschen */
       printf("\nSchreibfehler !\n");
       fclose(fp1);
       fclose(fp2);
       strcpy(del, "delete ");
       strcat(del, argv[2]);
       system(del);
       exit(0);
   }

   /* Statistik ausgeben */
   printf("%d Prozent\r", (int) ((double) (i + 1)
                       * buffsize / fsize * 100));
   fflush(stdout);
 }

 aus();
}
