diff --git a/Makefile b/Makefile index 95ad556..0d5ff24 100644 --- a/Makefile +++ b/Makefile @@ -2,18 +2,15 @@ CC = gcc CFLAGS = -OBJECTS := syscalls.o -EXEC := syscalls +EXEC := syscalls bscopy .PHONY: all clean all: $(EXEC) -%: %.o +%: %.c $(CC) $(CFLAGS) -o $@ $^ -%.o: %.c - $(CC) $(CFLAGS) -c -o $@ $< clean: - rm $(OBJECTS) $(EXEC) \ No newline at end of file + rm $(EXEC) \ No newline at end of file diff --git a/bscopy.c b/bscopy.c new file mode 100644 index 0000000..27deb5e --- /dev/null +++ b/bscopy.c @@ -0,0 +1,152 @@ +/* +-----------------------------------------------+ + | John Breaux - jab0910 - JohnBreaux@my.unt.edu | + | bscopy.c - CSCE4600 Homework 1 Question 4 | + +-----------------------------------------------+ */ + +#include // mkdir() +#include // opendir() +#include // atoi() +#include // fixed-width integer +#include // strerror(), strrchr() +#include // printf(), fopen(), fclose() +#include // errno +#include // clock() + +// F_ERROR: check file stream for errors; if error, print +#define F_ERROR(file_obj, ret) if (!file_obj) { printf ("%s: %s\n", #file_obj, strerror(ferror(file_obj)) ); return ret; } +#define MAX_BLOCK_SIZE 0x800 + +/* fcopy: copy in_filename to out_filename + args: + block: block size in bytes + in_filename: filename of the input file + out_filename: filename of the output file + returns: + size_t: number of bytes copied +*/ +size_t fcopy (size_t block, char* in_filename, char* out_filename); +/* fcreate: create a new file at filename, if it doesn't exist. + If file is attempted to be created in a nonexistent directory, + recursively create directories until the error is resolved. + I have no time for grading mistakes due to user error. + args: + size: size of file in bytes + filename: path to file + returns: + size_t: difference between number of bytes requested and actually created (should be zero) +*/ +int fcreate(size_t size, char* filename); + +int main (int argc, char** argv) { + int block_size = 1; + char *in = "/tmp/A", *out = "/tmp/B"; + // get argument "block size", "in", "out" from args + switch (argc) { + case 4: + out = argv[3]; + case 3: + in = argv[2]; + case 2: + block_size = atoi(argv[1]); + if (block_size > MAX_BLOCK_SIZE) { + printf ("%d too long (must not exceed %d)\n", block_size, MAX_BLOCK_SIZE); + block_size = MAX_BLOCK_SIZE; + } + break; + case 1: + default: + printf ("Usage: %s block_size [in [out]]\n", argv[0]); + exit (EXIT_FAILURE); + } + + + printf ("Copy %s to %s with blocksize of %d.\n", in, out, block_size); + // start the clock + clock_t time = clock(); + // perform the copy + int size = fcopy (block_size, in, out); + // stop the clock + time = clock() - time; + printf ("Copy of %.3f MBytes took %f seconds\n", (double)size / (1024*1024), (double) time / CLOCKS_PER_SEC); + exit (EXIT_SUCCESS); +} + +size_t fcopy (size_t block, char *in_filename, char *out_filename) { + FILE *in = fopen (in_filename, "r"); // Open in for reading + F_ERROR (in, 0); + FILE *out = fopen (out_filename, "w"); // Open out for writing + F_ERROR (out, 0); + // construct a buffer + uint8_t buffer[MAX_BLOCK_SIZE]; + size_t bytes_copied = 0; + // until end of file, + while (!feof(in)) { + // Read data from in + size_t bytes_read = fread(&buffer, block, 1, in); + // Write data to out + size_t bytes_written = fwrite(&buffer, bytes_read, 1, out); + // Make sure wrote same number of bytes as read + if (bytes_read == bytes_written) { + bytes_copied += bytes_read; + } else { + // Something's gone wrong + printf ("Copy: %ld not equal %ld! Aborting!\n", bytes_read, bytes_written); + bytes_copied = -bytes_copied; + break; + } + } + // Close the files + fclose(in); + fclose(out); + // Return bytes copied + return bytes_copied; +} + +int min(int a, int b) { + return (b-a >= 0)? a: b; +} + +// Recursive mkdir +int dircreate(char* path) { + while (mkdir(path, 0700)) { + switch (errno){ + case EEXIST: + return 0; + case ENOENT: { + char subpath[0x1000] = {0}, *last_slash; + size_t l = 0; + last_slash = strrchr(path, '/'); + l = path - (last_slash == NULL ? path : last_slash); + strncpy(subpath, path, min(l, 0x1000)); // construct the substring + dircreate(subpath); // recurse + } + default: + printf("Could not create directory: %s\n", strerror(errno)); + return -1; + } + } + return 0; +} + +int fcreate(size_t size, char* filename) { + // First, check if the directory exists + char* last_slash = strrchr(filename,'/'); + // find the length of the substring + int l = filename - (last_slash==NULL?filename:last_slash); + char path[0x1000] = {0}; + strncpy(path, filename, l); // construct the substring + dircreate(path); // recursively create new directories until satisfied + // then, try to create a file in that directory + uint8_t buffer[0x400] = {0}; // Assemble a buffer + FILE *file = fopen(filename, "w"); // Open for writing + F_ERROR(file, -1); // abort if error + // Copy 1024-byte chunks up until the desired filesize < 1024 bytes away + while (size > 0x400) { + size -= fwrite(buffer, 0x400, size/0x400, file); + } + // Copy the rest of the file + if (size > 0) { + size -= fwrite(buffer, size, 1, file); + } + return size; +}