From becc5a9dd968b0ed970d10cefcafb9cbf0af77a2 Mon Sep 17 00:00:00 2001
From: Brandon Rodriguez <brodriguez8774@gmail.com>
Date: Wed, 15 Nov 2017 13:26:26 -0500
Subject: [PATCH] Implement handling of multiple threads to read multiple files

---
 .../MyExamples/PassFirstLineInEachDirFile.c   | 274 ++++++++++++++++++
 Main.c                                        | 202 ++++++++++++-
 2 files changed, 465 insertions(+), 11 deletions(-)
 create mode 100644 Examples/MyExamples/PassFirstLineInEachDirFile.c

diff --git a/Examples/MyExamples/PassFirstLineInEachDirFile.c b/Examples/MyExamples/PassFirstLineInEachDirFile.c
new file mode 100644
index 0000000..85d68f7
--- /dev/null
+++ b/Examples/MyExamples/PassFirstLineInEachDirFile.c
@@ -0,0 +1,274 @@
+/**
+ * Brandon Rodriguez
+ * CS 3240
+ * 11-15-17
+ * a4 (Assignment 5)
+ */
+
+
+/**
+ * Description:
+ *  Testing of thread implementation to solve a problem.
+ *  Slightly more advanced example of joining with data passing.
+ *
+ *  This reads in a provided directory and opens up threads equivalent to the number of
+ *  files within. Each process handles a diffierent file, grabbing the first line,
+ *  reading it, then returning the line to main which reads line again.
+ */
+
+
+/**
+ * Known Issues:
+ *  No valgrind issues in small-data folder but valgrind finds four issues
+ *  in large-data folder. Not sure where the errors are comming from, as valgrind
+ *  (seemingly?) doesn't even point to any lines of code for this issue. Baffling.
+ */
+
+
+#define _BSD_SOURCE
+
+// Import headers.
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include "apue.h"
+#include "HelperHeader.h"
+
+
+// Define Vars.
+#define BUFFER_SIZE 4096
+
+
+// Variables.
+typedef struct{
+    char* user_name;
+    char* password;
+    char* blood_type;
+    char* domain_name;
+    int db_index;
+} data_struct;
+int dir_file_counter;
+char* absolute_path;
+pthread_t* thread_array;
+
+
+// Method Declaration.
+int change_directory();
+void open_folder();
+void* thread_read_file();        // Reads given file and reorganizes data.
+
+
+/**
+ * Program's main.
+ * Initializes and runs program.
+ */
+int main(int argc, char* argv[]) {
+    int index;
+    int return_int;
+    char* return_string;
+
+    // Check for valid args.
+    if (argc < 2) {
+        err_msg("Must enter a directory path.");
+        return -1;
+    } else if (argc > 2) {
+        err_msg("Must enter exacly one directory path.");
+        return -1;
+    } else {
+
+        return_int = change_directory(argv[1]);
+        if (return_int == 0) {
+            // Get absolute path.
+            absolute_path = calloc(BUFFER_SIZE, sizeof(char*));
+            if (getcwd(absolute_path, BUFFER_SIZE) == NULL) {
+                err_sys("Failed to get absolute path.");
+            }
+
+            // Open folder and create appropriate number of threads.
+            open_folder();
+
+            // Iterate through all threads and grab returned value.
+            for (index = 0; index < dir_file_counter; index++) {
+                pthread_join(thread_array[index], (void**) &return_string);
+                printf("Thread returned: %s", return_string);
+                free(return_string);
+            }
+
+            free(absolute_path);
+            free(thread_array);
+        }
+    }
+
+    return 0;
+}
+
+
+/**
+ * Safely changes directory by first checking path value and permissions.
+ *
+ * Returns 0 on success or -1 on failure.
+ */
+int change_directory(char* folder_location) {
+    int return_int;
+    struct stat stat_buffer;
+
+    return_int =lstat(folder_location, &stat_buffer);
+    if (return_int <0) {
+        err_sys("Failed to stat file with err %d", return_int);
+        return -1;
+    }
+
+    // First, ensure that it is, infact, a directory.
+    if (S_ISDIR(stat_buffer.st_mode)) {
+        // Next, check permissions.
+        if (access(folder_location, X_OK) == 0) {
+            // Change into directory.
+            return_int = chdir(folder_location);
+            if (return_int < 0) {
+                err_sys("Failed to change directory with err %d", return_int);
+                return -1;
+            }
+        } else { // No execute permission.
+            err_msg("No execute permission. Cannot change into directory.\n");
+            return -1;
+        }
+    } else { // Not a dir.
+        err_msg("Provided path is not a directory.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Opens indicated folder and hands files off to threads.
+ */
+void open_folder() {
+    int index;
+    int return_int;
+    char* temp_string;
+    struct dirent* dir_struct;
+    struct stat stat_buffer;
+    DIR* dir_pointer;
+
+    // Iterate through directory first time, to count number of files to open/threads to make.
+    dir_file_counter = 0;
+    dir_pointer = opendir(absolute_path);
+
+    // Check that directory has read permissions.
+    if (access(absolute_path, R_OK) == 0) {
+
+        // Loop until no more files in directory.
+        while (dir_pointer != NULL) {
+            if ((dir_struct = readdir(dir_pointer)) != NULL) {
+
+                // New file found. Check if standard file type.
+                return_int = lstat(dir_struct->d_name, &stat_buffer);
+                if (return_int < 0) {
+                    err_sys("Failed to stat file with err %d", return_int);
+                }
+                if (S_ISREG(stat_buffer.st_mode)) {
+                    dir_file_counter++;
+                }
+            } else {
+                // End of files in directory. Closing stream.
+                return_int = closedir(dir_pointer);
+                if (return_int < 0) {
+                    err_msg("Failed to properly close directory.");
+                }
+                dir_pointer = NULL;
+            }
+        }
+    } else {
+        err_msg("Directory does not have read access. Cannot view files.");
+    }
+    printf("Directory File Counter: %d\n", dir_file_counter);
+
+
+    // Prepare to set up threads.
+    thread_array = calloc(dir_file_counter, sizeof(pthread_t));
+    index = 0;
+    pthread_attr_t attr;
+    size_t stacksize;
+
+    pthread_attr_init(&attr);
+    pthread_attr_getstacksize(&attr, &stacksize);
+    if (stacksize < 8388608) {
+        stacksize = 8388608;
+    }
+    pthread_attr_setstacksize(&attr, (stacksize * 2));
+
+
+    // Iterate through directory again. This time, actually create threads and hand off files.
+    dir_pointer = opendir(absolute_path);
+
+    // Check that directory has read permissions.
+    if (access(absolute_path, R_OK) == 0) {
+
+        // Loop until no more files in directory.
+        while (dir_pointer != NULL) {
+            if ((dir_struct = readdir(dir_pointer)) != NULL) {
+
+                // New file found. Check if standard file type.
+                return_int = lstat(dir_struct->d_name, &stat_buffer);
+                if (return_int < 0) {
+                    err_sys("Failed to stat file with err %d", return_int);
+                }
+                if (S_ISREG(stat_buffer.st_mode)) {
+
+                    // Get absolute file path.
+                    temp_string = copy_string_with_buffer(absolute_path, BUFFER_SIZE);
+                    strcat(temp_string, "/");
+                    strcat(temp_string, dir_struct->d_name);
+                    printf("Path: %s\n", temp_string);
+
+                    // Actually create threads.
+                    pthread_create(&thread_array[index], &attr, thread_read_file, (void*) copy_string(temp_string));
+                    index++;
+                    free(temp_string);
+                }
+            } else {
+                // End of files in directory. Closing stream.
+                return_int = closedir(dir_pointer);
+                if (return_int < 0) {
+                    err_msg("Failed to properly close directory.");
+                }
+                dir_pointer = NULL;
+            }
+        }
+    } else {
+        err_msg("Directory does not have read access. Cannot view files.");
+    }
+
+}
+
+
+/**
+ * Uses thread to read file value.
+ */
+void* thread_read_file(void* file_location) {
+    FILE* read_file;
+    char* line_buffer = calloc(BUFFER_SIZE, sizeof(char*));
+    int result_int;
+
+    // printf("I'ma child and I was given dis: %s\n", file_location);
+    // pthread_exit(file_location);
+
+    read_file = fopen(file_location, "r");
+    fgets(line_buffer, BUFFER_SIZE, read_file);
+    free(file_location);
+    result_int = fclose(read_file);
+    if (result_int != 0) {
+        err_msg("Failed to close file properly.");
+    }
+
+    printf("I'ma child and I found dis: %s", line_buffer);
+
+    pthread_exit(line_buffer);
+}
diff --git a/Main.c b/Main.c
index ca6b80f..132e9b8 100644
--- a/Main.c
+++ b/Main.c
@@ -27,14 +27,19 @@
  */
 
 
+#define _BSD_SOURCE
+
 // Import headers.
 #include <ctype.h>
+#include <dirent.h>
 #include <fcntl.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <sys/stat.h>
 #include "apue.h"
+#include "HelperHeader.h"
 
 
 // Define Vars.
@@ -49,10 +54,15 @@ typedef struct{
     char* domain_name;
     int db_index;
 } data_struct;
+int dir_file_counter;
+char* absolute_path;
+pthread_t* thread_array;
 
 
 // Method Declaration.
-void* ThreadReadFile();        // Reads given file and reorganizes data.
+int change_directory();
+void open_folder();
+void* thread_read_file();        // Reads given file and reorganizes data.
 
 
 /**
@@ -60,34 +70,204 @@ void* ThreadReadFile();        // Reads given file and reorganizes data.
  * Initializes and runs program.
  */
 int main(int argc, char* argv[]) {
-    pthread_t thread;
-
-    char* file_location = "Data/small-data/0";
+    int index;
+    int return_int;
     char* return_string;
 
-    pthread_create(&thread, NULL, ThreadReadFile, (void*) file_location);
-    pthread_join(thread, (void**) &return_string);
-    printf("Thread returned:\n%s", return_string);
-    free(return_string);
+    // Check for valid args.
+    if (argc < 2) {
+        err_msg("Must enter a directory path.");
+        return -1;
+    } else if (argc > 2) {
+        err_msg("Must enter exacly one directory path.");
+        return -1;
+    } else {
+
+        return_int = change_directory(argv[1]);
+        if (return_int == 0) {
+            // Get absolute path.
+            absolute_path = calloc(BUFFER_SIZE, sizeof(char*));
+            if (getcwd(absolute_path, BUFFER_SIZE) == NULL) {
+                err_sys("Failed to get absolute path.");
+            }
+
+            // Open folder and create appropriate number of threads.
+            open_folder();
+
+            // Iterate through all threads and grab returned value.
+            for (index = 0; index < dir_file_counter; index++) {
+                pthread_join(thread_array[index], (void**) &return_string);
+                printf("Thread returned: %s", return_string);
+                free(return_string);
+            }
+
+            free(absolute_path);
+            free(thread_array);
+        }
+    }
+
+    return 0;
+}
+
+
+/**
+ * Safely changes directory by first checking path value and permissions.
+ *
+ * Returns 0 on success or -1 on failure.
+ */
+int change_directory(char* folder_location) {
+    int return_int;
+    struct stat stat_buffer;
+
+    return_int =lstat(folder_location, &stat_buffer);
+    if (return_int <0) {
+        err_sys("Failed to stat file with err %d", return_int);
+        return -1;
+    }
+
+    // First, ensure that it is, infact, a directory.
+    if (S_ISDIR(stat_buffer.st_mode)) {
+        // Next, check permissions.
+        if (access(folder_location, X_OK) == 0) {
+            // Change into directory.
+            return_int = chdir(folder_location);
+            if (return_int < 0) {
+                err_sys("Failed to change directory with err %d", return_int);
+                return -1;
+            }
+        } else { // No execute permission.
+            err_msg("No execute permission. Cannot change into directory.\n");
+            return -1;
+        }
+    } else { // Not a dir.
+        err_msg("Provided path is not a directory.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/**
+ * Opens indicated folder and hands files off to threads.
+ */
+void open_folder() {
+    int index;
+    int return_int;
+    char* temp_string;
+    struct dirent* dir_struct;
+    struct stat stat_buffer;
+    DIR* dir_pointer;
+
+    // Iterate through directory first time, to count number of files to open/threads to make.
+    dir_file_counter = 0;
+    dir_pointer = opendir(absolute_path);
+
+    // Check that directory has read permissions.
+    if (access(absolute_path, R_OK) == 0) {
+
+        // Loop until no more files in directory.
+        while (dir_pointer != NULL) {
+            if ((dir_struct = readdir(dir_pointer)) != NULL) {
+
+                // New file found. Check if standard file type.
+                return_int = lstat(dir_struct->d_name, &stat_buffer);
+                if (return_int < 0) {
+                    err_sys("Failed to stat file with err %d", return_int);
+                }
+                if (S_ISREG(stat_buffer.st_mode)) {
+                    dir_file_counter++;
+                }
+            } else {
+                // End of files in directory. Closing stream.
+                return_int = closedir(dir_pointer);
+                if (return_int < 0) {
+                    err_msg("Failed to properly close directory.");
+                }
+                dir_pointer = NULL;
+            }
+        }
+    } else {
+        err_msg("Directory does not have read access. Cannot view files.");
+    }
+    printf("Directory File Counter: %d\n", dir_file_counter);
+
+
+    // Prepare to set up threads.
+    thread_array = calloc(dir_file_counter, sizeof(pthread_t));
+    index = 0;
+    pthread_attr_t attr;
+    size_t stacksize;
+
+    pthread_attr_init(&attr);
+    pthread_attr_getstacksize(&attr, &stacksize);
+    if (stacksize < 8388608) {
+        stacksize = 8388608;
+    }
+    pthread_attr_setstacksize(&attr, (stacksize * 2));
+
+
+    // Iterate through directory again. This time, actually create threads and hand off files.
+    dir_pointer = opendir(absolute_path);
+
+    // Check that directory has read permissions.
+    if (access(absolute_path, R_OK) == 0) {
+
+        // Loop until no more files in directory.
+        while (dir_pointer != NULL) {
+            if ((dir_struct = readdir(dir_pointer)) != NULL) {
+
+                // New file found. Check if standard file type.
+                return_int = lstat(dir_struct->d_name, &stat_buffer);
+                if (return_int < 0) {
+                    err_sys("Failed to stat file with err %d", return_int);
+                }
+                if (S_ISREG(stat_buffer.st_mode)) {
+
+                    // Get absolute file path.
+                    temp_string = copy_string_with_buffer(absolute_path, BUFFER_SIZE);
+                    strcat(temp_string, "/");
+                    strcat(temp_string, dir_struct->d_name);
+                    printf("Path: %s\n", temp_string);
+
+                    // Actually create threads.
+                    pthread_create(&thread_array[index], &attr, thread_read_file, (void*) copy_string(temp_string));
+                    index++;
+                    free(temp_string);
+                }
+            } else {
+                // End of files in directory. Closing stream.
+                return_int = closedir(dir_pointer);
+                if (return_int < 0) {
+                    err_msg("Failed to properly close directory.");
+                }
+                dir_pointer = NULL;
+            }
+        }
+    } else {
+        err_msg("Directory does not have read access. Cannot view files.");
+    }
+
 }
 
 
 /**
  * Uses thread to read file value.
  */
-void* ThreadReadFile(void* file_location) {
+void* thread_read_file(void* file_location) {
     FILE* read_file;
     char* line_buffer = calloc(BUFFER_SIZE, sizeof(char*));
     int result_int;
 
     read_file = fopen(file_location, "r");
     fgets(line_buffer, BUFFER_SIZE, read_file);
+    free(file_location);
     result_int = fclose(read_file);
     if (result_int != 0) {
-        err_sys("Failed to close file properly.");
+        err_msg("Failed to close file properly.");
     }
 
-    printf("I'ma child and I found dis: \n%s\n", line_buffer);
+    printf("I'ma child and I found dis: %s", line_buffer);
 
     pthread_exit(line_buffer);
 }
-- 
GitLab