/**
 * File: copy-extended.c
 * --------------
 * This program is an implementation of an extended copy command that shows how we can
 * make a copy of a specified file into multiple other specified files, as well
 * as printing the contents to the terminal.  Right now it's the solution from the
 * copy.c program; our task is to build on it!  (Note: you may assume you do not need
 * to add error-checking for open/close/read/write in your solution).
 */

#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>

// The permissions to set if the destination file doesn't exist
static const int kDefaultPermissions = 0644;  // number equivalent of "rw-r--r--"

// The number of bytes we copy at once from source to destination
static const int kCopyIncrement = 1024;

/* This is a helper function wrapper around `write` that guarantees the first
 * nbytes bytes in buffer will be written to destinationFD (unless write
 * encounters an error and returns -1 - in this implementation, this is
 * assumed not to happen).
 */
void writeAllBytes(int destinationFD, char buffer[], size_t nbytes) {
    size_t bytesWritten = 0;
    while (bytesWritten < nbytes) {
        ssize_t count = write(destinationFD, buffer + bytesWritten, nbytes - bytesWritten);
        bytesWritten += count;
    }
}

/* This function copies the contents of the source file into each destination
 * file in chunks until the entire file is copied.
 */
void copyContents(int sourceFD, int destinationFD) {
    while (true) {
        char buffer[kCopyIncrement];

        // Read the next chunk of bytes from the source
        ssize_t bytesRead = read(sourceFD, buffer, sizeof(buffer));

        // check if we are at the end of the file
        if (bytesRead == 0) break;

        writeAllBytes(destinationFD, buffer, bytesRead);
    }
}

int main(int argc, char *argv[]) {
    // Open the specified source file for reading
    int sourceFD = open(argv[1], O_RDONLY);

    // Open the specified destination file for writing, creating if nonexistent
    int destinationFD = open(argv[2], O_WRONLY | O_CREAT | O_EXCL, kDefaultPermissions);

    copyContents(sourceFD, destinationFD);

    // Close the source and destination files
    close(sourceFD);
    close(destinationFD);

    return 0;
}
