From 6e3e702a888b065050a6473c1b0bcea39d431519 Mon Sep 17 00:00:00 2001 From: Amber Date: Sun, 21 Feb 2021 21:23:32 -0500 Subject: [PATCH] Initial commit. --- programming-assignment.c | 249 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 programming-assignment.c diff --git a/programming-assignment.c b/programming-assignment.c new file mode 100644 index 0000000..d723e0d --- /dev/null +++ b/programming-assignment.c @@ -0,0 +1,249 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************** + * Authors: Gary Fleming, Amber McCloughan + * Class: CIS452 - Operating Systems Concepts + * Professor: Dr. Greg Wolffe + * Date: 4/18/2019 + * + * Program that mimics basic ls functionality. Depending on the flags + * passed into the program, we display information about a directory's + * files. We try and ensure that the output is human readable, so a + * user can easily summarize the contents of a directory. + * + * Arguments + * ------------------------------------------------------------------------- + * -i : Displays the inode number along with basic output. + * -n : Displays user and group ID for each file, along with + * some other basic information. + * [directory] : Input a directory name as an argument to display + * information about a directory other than the one + * you're currently in. + ***************************************************************************/ + +// Max size of a timestamp. +#define MAX_TIMESTAMP_LEN 255 + +// Max size of a character buffer. +#define MAX_BUF_LEN 1024 + +/** + * Main function of the program. Takes in + * three possible arguments: -i, -n, and + * the name of a directory. + * + * @param argc, number of arguments. + * @param argv, the actual arguments. + */ +int main(int argc, char *argv[]) +{ + // Integer used in for loop. + int i; + + // Flag that is set to 1 if -n is used. + int nFlag = 0; + + // Flag that is set to 1 if -i is used. + int iFlag = 0; + + // For use with symbolic links. + char *linkName; + + // Buffer for formatting time information. + char *timeBuf = malloc(MAX_TIMESTAMP_LEN * sizeof(char)); + + // Buffer for holding the directory we're concerned with. + char *direct = malloc(MAX_BUF_LEN * sizeof(char)); + + // File name buffer. + char *fileName = malloc(MAX_BUF_LEN * sizeof(char)); + + // For the fully-qualified path. + char *fulQual; + + // Used in getting the fully-qualified path. + char actualPath[PATH_MAX + 1]; + + // Copying initial value into directory. + strcpy(direct, "."); + + // Reading the program arguments. + for (i = 1; i < argc; i++) + { + // If we found the -i flag. + if (!strcmp(argv[i], "-i")) + { + iFlag = 1; + } + // If we found the -n flag. + else if (!strcmp(argv[i], "-n")) + { + nFlag = 1; + } + // If we found a combination of flags. + else if (!strcmp(argv[i], "-in") || !strcmp(argv[i], "-ni")) + { + nFlag = 1; + iFlag = 1; + } + // Anything else must be the directory. + else + { + strcpy(direct, argv[i]); + } + } + + // Buffer for file statistics. + struct stat statBuf; + + // Directory pointer. + DIR *dirPtr; + + // Directory stream pointer. + struct dirent *entryPtr; + + // Opening directory stream. + dirPtr = opendir(direct); + + // If the directory could not be read (not found or improperly formatted). + if (dirPtr == NULL) + { + // Error message. + printf("An error occured while attempting to open directory.\n"); + + // Freeing resources. + free(timeBuf); + free(direct); + free(fileName); + + // Goodbye. + return -1; + } + + // Iterating over the directory's files. + while ((entryPtr = readdir(dirPtr))) + { + // Creating the full relative path. + strcpy(fileName, direct); + strcat(fileName, "/"); + strcat(fileName, entryPtr->d_name); + + /* + * Getting the fully-qualified path name. I learned how to do + * this using the following link: + * https://stackoverflow.com/questions/229012/ + */ + fulQual = realpath(fileName, actualPath); + + // Checking if the file is a soft link. + if (entryPtr->d_type == DT_LNK) + { + // Getting link statistics. + if (lstat(fileName, &statBuf) < 0) + { + free(timeBuf); + free(direct); + free(fileName); + perror("huh? there is "); + exit(1); + } + + // Allocating buffer for where the link leads. + linkName = malloc(statBuf.st_size + 1); + + // Getting where the link leads. + if (readlink(fileName, linkName, statBuf.st_size + 1) < 0) + { + free(timeBuf); + free(direct); + free(fileName); + free(linkName); + perror("huh? there is "); + exit(1); + } + + // Adding a null-terminating character. + linkName[statBuf.st_size] = '\0'; + + // Creating a special link name for -n. + strcpy(fileName, entryPtr->d_name); + strcat(fileName, " -> "); + strcat(fileName, linkName); + + free(linkName); + } + else + { + // Name for non-link files. + strcpy(fileName, entryPtr->d_name); + + // Grabbing stats for non-link files. + if (stat(fulQual, &statBuf) < 0) + { + free(timeBuf); + free(direct); + free(fileName); + perror("huh? there is "); + exit(1); + } + } + + // Don't display the current directory or previous directory files. + if (!strcmp(entryPtr->d_name, ".") || !strcmp(entryPtr->d_name, "..")) + { + continue; + } + + /* + * We figured out how to format time using the article below. + * We have to convert the time_t type into a tm, which takes + * a few steps. Then, we utilize the strftime() function to + * format the time into a user-readable string. + * https://stackoverflow.com/questions/13542345 + */ + time_t t = statBuf.st_mtime; + struct tm lt; + localtime_r(&t, <); + strftime(timeBuf, MAX_TIMESTAMP_LEN * sizeof(char), "%b %d, %Y %X", <); + + // Changing name if we aren't using -n. + if (nFlag == 0) + { + strcpy(fileName, entryPtr->d_name); + } + + // For no flags. + if (iFlag == 0 && nFlag == 0) + printf("%s\n", fileName); + // For only the -i flag. + else if (iFlag == 1 && nFlag == 0) + printf("%lu %s\n", entryPtr->d_ino, fileName); + // For only the -n flag. + else if (iFlag == 0 && nFlag == 1) + printf("%o | %lu | %d | %d | %ld | %s | %s\n", statBuf.st_mode, statBuf.st_nlink, statBuf.st_uid, statBuf.st_gid, statBuf.st_size, timeBuf, fileName); + // For both flags. + else if (iFlag == 1 && nFlag == 1) + printf("%lu | %o | %lu | %d | %d | %ld | %s | %s\n", entryPtr->d_ino, statBuf.st_mode, statBuf.st_nlink, statBuf.st_uid, statBuf.st_gid, statBuf.st_size, timeBuf, fileName); + } + + // Closing stream. + closedir(dirPtr); + + // Freeing resources. + free(timeBuf); + free(direct); + free(fileName); + + // Goodbye. + return 0; +} \ No newline at end of file