summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fileutil.c92
-rw-r--r--fileutil.h21
2 files changed, 79 insertions, 34 deletions
diff --git a/fileutil.c b/fileutil.c
index fa1ccac..855df21 100644
--- a/fileutil.c
+++ b/fileutil.c
@@ -4,7 +4,7 @@
* Alexander Occhipinti
* Student ID: 29994705
* Created: 3 Sep 2020
- * Last Modified: 7 Sep 2020
+ * Last Modified: 8 Sep 2020
*
* fileutil is a program which is a utility for files. It combines the functionality of cat cp and mv.
* This program allows you to copy the contents of a given file to stdout or to a another file.
@@ -34,11 +34,12 @@ void to_stderr(char *string) {
write(2, string, strlen(string));
}
+
/*
- * Prints the contents of a given file (provided a path) to stdout.
- * Returns nothing.
+ * Given a file path and open() flags, open a file
+ * Catches openning errors, prints an error to stderr when an error occurs and exits
+ * Returns a file descriptor of the open file. Needs to be closed afterwards.
*/
-
int open_file(char *path, int flags){
// Read the input file
int fd;
@@ -47,11 +48,18 @@ int open_file(char *path, int flags){
to_stderr(path);
to_stderr(" could not be opened: ");
to_stderr(strerror(error));
- exit(1); // Exit if an error occurs
+ // Exit (with 1) if an error occurs, with error 2 if the file exists and can not be overwriten
+ if (errno == EEXIST) exit(2) : exit(1);
}
return fd;
}
+/*
+ * Given a source file descriptor open for reading,
+ * put all of its contents in the destination file descriptor open for writing.
+ *
+ * Useful for transferring data between files or stdin/stdout/stderr
+*/
void file_into_file(int source_fd, int dest_fd){
int bytes_read;
char buffer[FILE_BUF_SIZE];
@@ -61,6 +69,10 @@ void file_into_file(int source_fd, int dest_fd){
}
+/*
+ * Prints the contents of a given file (provided a path) to stdout.
+ * Returns nothing.
+*/
void print_file(char *read_path) {
int read_fd;
read_fd = open_file(read_path, O_RDONLY);
@@ -68,20 +80,31 @@ void print_file(char *read_path) {
close(read_fd);
}
+/*
+ * Copy a file from the read_path to the write_path, prints an error to stderr and quits if
+ * there is an error with opening. Overwrites the target file only if bool overwrite is true, throws an error otherwise.
+ *
+*/
void copy_file(char *read_path, char *write_path, bool overwrite) {
int read_fd, write_fd;
int write_flags = O_WRONLY | O_CREAT | O_TRUNC;
- if (!overwrite) write_flags |= O_EXCL;
+ if (!overwrite) write_flags |= O_EXCL; // Add no-clobber flag if not allowed to overwrite
+ // Open both files
read_fd = open_file(read_path, O_RDONLY);
write_fd = open_file(write_path, write_flags);
- file_into_file(read_fd, write_fd);
+ file_into_file(read_fd, write_fd); // Write one file into the other
+ // Close both files
close(read_fd);
close(write_fd);
}
+/*
+ * Provided a string of an absolute path, returns a pointer to the same string representing
+ * a string of just the filename.
+*/
char* get_filename(char *full_path){
char* filename = strrchr(full_path, '/'); // Find the string after the last occurence of a '/'
if (!filename) return full_path; // If there are no slashes, the whole path is already a filename
@@ -89,30 +112,46 @@ char* get_filename(char *full_path){
}
+/*
+* Returns true if the provided string is a UNIX style absolute path (starts with '/'), false otherwise
+*/
bool is_a_path(char* string) {
return (strlen(string) == 0) ? false : string[0] == '/';
}
+/*
+ * Copies a file given the path `file_path`, into the directory of path string `dir_path`
+ * Moves the file rather than copies it (i.e. remove the original file) if `move` is true
+ * Overwrites the target file if it exists if `overwrite` is true
+*/
void copy_into_dir(char *file_path, char *dir_path, bool move, bool overwrite){
char* filename;
char* new_path;
size_t new_path_len;
+ // Construct the absolute path of the new file in the directory specified, allocate memory
filename = get_filename(file_path);
new_path_len = strlen(dir_path) + strlen(filename) + 1;
new_path = (char *) malloc(new_path_len);
-
+ // Combine/concat the parts of the new filename
strcpy(new_path, dir_path);
strcat(new_path, "/");
strcat(new_path, filename);
+
copy_file(file_path, new_path, overwrite);
- if (move) unlink(file_path);
+ if (move) unlink(file_path); // Delete the original if `move` is specified
to_stdout("Copy successful\n");
free(new_path);
}
+/*
+ * Given argc and argv (number of program arguments and the program arguments) provided from main,
+ * create an `arguments_t` type struct containing all of the information about the arguments.
+ * If the given arguments are invalid, the `.valid` attribute of the return value is false.
+*/
arguments_t parse_arguments(int argc, char **argv){
+ // Create a fresh arguments_t struct
arguments_t args = {
.src_index = -1,
.dir_index = -1,
@@ -122,6 +161,7 @@ arguments_t parse_arguments(int argc, char **argv){
.dir_flag = false
};
+ // Go through each argument, find the defined flags and store then in the struct
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-d") == 0) {
args.dir_flag = true;
@@ -133,57 +173,57 @@ arguments_t parse_arguments(int argc, char **argv){
}
}
- if (argc > 1 && is_a_path(argv[1])) args.src_index = 1;
+ // Determine if the source path is either not provided or the first argument
+ if (argc > 1 && is_a_path(argv[1])) args.src_index = 1;
+ // Is a valid combination of flags provided?
bool correct_flags = (args.move_flag || args.force_flag) ? args.dir_flag : true;
- bool correct_directory = false;
+ // Is the -d tag followed by a path?
+ bool correct_directory = false;
if (args.dir_index < argc) {
correct_directory = (args.dir_flag) ? is_a_path(argv[args.dir_index]) : true;
}
+ // Combine all conditions for a valid set of arguments
args.valid =
correct_flags &&
correct_directory &&
(argc >= MIN_NUM_OF_ARGS) &&
(argc <= MAX_NUM_OF_ARGS);
-
return args;
}
+/*
+ * Given an arguments_t struct of the program's arguments, execute the correct suprogram
+ * (i.e. move, copy or print to stdout)
+*/
void execute_subprogram(arguments_t args, char *argv[]) {
+
+ // Abort program if invalid arguments specified
if (!args.valid) {
to_stderr("Invalid arguments given.\n");
exit(1);
}
+ // Set the source_path to the default read path if it's not defined
char *source_path = (args.src_index == -1 ) ? DEFAULT_READ_PATH : argv[args.src_index];
char *dir_path;
- if (args.dir_flag){
+ if (args.dir_flag){ // Copy/move a file into a directory
dir_path = argv[args.dir_index];
copy_into_dir(source_path, dir_path, args.move_flag, args.force_flag);
} else {
- print_file(source_path);
+ print_file(source_path); // Print a file
}
}
-
-
-
-
-
+// Main
int main(int argc, char *argv[]) {
arguments_t args = parse_arguments(argc, argv);
- if (!args.valid) {
- to_stderr("Invalid arguments provided.");
- return 1;
- } else {
- execute_subprogram(args, argv);
- }
-
+ execute_subprogram(args, argv);
return 0;
}
diff --git a/fileutil.h b/fileutil.h
index 9d7d75b..fbfb27c 100644
--- a/fileutil.h
+++ b/fileutil.h
@@ -2,19 +2,21 @@
#define _FILEUTIL_H
#define FILE_BUF_SIZE 1024
-#define DEFAULT_READ_PATH "logfile.txt"
-#define NEW_FILE_PERMS 0664
+#define DEFAULT_READ_PATH "logfile.txt" // Default source path if one isn't specified
+#define NEW_FILE_PERMS 0664 // -rw-r--r-- when files are created
#define MIN_NUM_OF_ARGS 1
#define MAX_NUM_OF_ARGS 6
typedef enum {false, true} bool;
+
+// A struct type which represents the arguments/flags provided to the program
typedef struct arguments_t {
- bool valid;
- bool move_flag;
- bool force_flag;
- bool dir_flag;
- int src_index;
- int dir_index;
+ bool valid; // Is this a valid combination of arguments?
+ bool move_flag; // Is the move flag specified? (-M)
+ bool force_flag; // Is the force flag specified? (-F)
+ bool dir_flag; // Is the directory flag specified? (-d)
+ int src_index; // Index in the provided arguments (argv) of the source path string
+ int dir_index; // Index in the provided arguments (argv) of the directory path string
} arguments_t;
void to_stdout(char *string);
@@ -24,7 +26,10 @@ void file_into_file(int source_fd, int dest_fd);
void print_file(char *read_path);
void copy_file(char *read_path, char *write_path, bool overwrite);
char* get_filename(char *full_path);
+bool is_a_path(char* string);
void copy_into_dir(char *file_path, char *dir_path, bool move, bool overwrite);
+arguments_t parse_arguments(int argc, char **argv);
+void execute_subprogram(arguments_t args, char *argv[]);
int main(int argc, char *argv[]);
#endif \ No newline at end of file