4600-homework-1/bscopy.c

175 lines
5.7 KiB
C

/* +-----------------------------------------------+
| John Breaux - jab0910 - JohnBreaux@my.unt.edu |
| bscopy.c - CSCE4600 Homework 1 Question 4 |
+-----------------------------------------------+ */
#include <sys/stat.h> // mkdir()
#include <dirent.h> // opendir()
#include <stdlib.h> // atoi()
#include <stdint.h> // fixed-width integer
#include <string.h> // strerror(), strrchr()
#include <stdio.h> // printf(), fopen(), fclose()
#include <errno.h> // errno
#include <time.h> // 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.
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);
/* dircreate: recursive mkdir (aka mkdir -p)
args:
path: path to directory
returns:
depth: number of directories created
*/
int dircreate(char* path);
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);
*/
// Test dircreate
printf("dircreate returned %d\n",dircreate(out));
}
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_recurse(char* path, int depth) {
if (depth == 2) {
printf("If you see this message, you've asked to create an awful lot of directories.\n");
}
while (mkdir(path, 0700)) {
switch (errno){
case EEXIST:
// path exists. Success!
return depth;
case ENOENT: {
char subpath[0x1000] = {0}, *last_slash;
size_t l = 0;
// get the length of the substring
last_slash = strrchr(path, '/');
l = (last_slash == NULL ? path : last_slash) - path;
strncpy(subpath, path, min(l, 0x1000)); // construct the substring
depth++;
// if at first you don't succeed, try and try again
depth = dircreate_recurse(subpath, depth); // recurse
break;
}
default:
printf("Could not create directory %s: Error %d (%s)\n", path, errno, strerror(errno));
return -1;
}
}
return depth;
}
// wrap dircreate_recurse
int dircreate(char* path) {
return dircreate_recurse(path, 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 the number of unwritten bytes, if any
return size;
}