/* a program to create a posix thread  */
/* link to the pthreads library with -lpthread */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
pthread_t copy_tid;

#define MAXCOPIERS 10
#define BUFSIZE 100

void *copy_file(void *arg);

int main(int argc, char *argv[])
{
    pthread_t tid[MAXCOPIERS]; /* 10 possible threads */
    int fd[MAXCOPIERS][2];     /* each thread has 2 file descriptors */

    char filename[80];

    int numcopiers;
    int total_bytes_copied = 0;
    int *bytes_copied_p;
    int i;

    if (argc != 4) {
       fprintf(stderr,"usage: %s infile_name outfile_name, copiers\n",
               argv[0]);
       exit(0);
    }
    numcopiers = atoi(argv[3]);
    if (numcopiers < 1 || numcopiers > MAXCOPIERS) {
       fprintf(stderr, "%d invalid number of copiers\n",numcopiers);
       exit(0);
    }
    for (i=0;i<numcopiers;i++) {
        sprintf(filename,"%s.%d",argv[1],i);
        if ((fd[i][0] = open(filename, O_RDONLY)) < 0) {
            fprintf(stderr,"Unable to open copy source file %s: %s\n",
                    filename, strerror(errno));
            continue;
        }
        sprintf(filename,"%s.%d",argv[2],i);
        if ((fd[i][1] = open(filename, O_WRONLY | O_CREAT,
                             S_IRUSR | S_IWUSR)) < 0) {
            fprintf(stderr, "Unable to create copy destination file %s: %s\n",
                filename, strerror(errno));
            continue;
        }
        if (pthread_create(&tid[i], NULL, copy_file, (void *)fd[i]) != 0)
            fprintf(stderr,"Could not create thread %i: %s\n",
            i, strerror(errno));
    }
    /* wait for copies to complete */

    for (i=0;i<numcopiers;i++) {
      if (pthread_join(tid[i],(void **)&(bytes_copied_p)) != 0)
         fprintf(stderr,"No thread %d to join: %s\n",
                 i, strerror(errno));
      else {
         printf("Thread %d copied %d bytes from %s.%d to %s.%d\n",
               i, *bytes_copied_p, argv[1],i,argv[2],i);
         total_bytes_copied += *bytes_copied_p;
      }
    }
    printf("Total bytes copied = %d\n",total_bytes_copied);
    exit(0);
}

void *copy_file(void *arg)
{
    int infile, outfile;
    int bytes_read = 0;
    int bytes_written = 0;
    int *bytes_copied_p;
    char buffer[BUFSIZE];
    char *bufp;

    infile = *((int *)(arg));
    outfile = *((int *)(arg)+1);
    bytes_copied_p = (int *)malloc(sizeof(int));
    if (bytes_copied_p == NULL)
       pthread_exit(NULL);
    *bytes_copied_p = 0;
    while (1) {
         bytes_read = read(infile, buffer, BUFSIZE);
         if ((bytes_read == 0) || ((bytes_read < 0) && (errno != EINTR)) )
            break;
         else if ((bytes_read < 0) && (errno == EINTR))
            continue;
            bufp = buffer;
         while (bytes_read > 0) {
            bytes_written = write(outfile, bufp, bytes_read);
            if ((bytes_written < 0) && (errno != EINTR))
                break;
            else if (bytes_written < 0)
                continue;
            *bytes_copied_p += bytes_written;
            bytes_read -= bytes_written;
            bufp += bytes_written;
         }
         if (bytes_written < 0) 
            break;
    }
    close(infile);
    close(outfile);
    pthread_exit(bytes_copied_p);
}
