/* +-----------------------------------------------+ | 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; }