#include #include #include #include #include #include #include "stuffy.h" // Put a module header into a HeaderStruct and read (skip) module data // Returns size of data read when reading a module header int ReadSingleModule(int fd, ModuleStruct* module) { int readSize; long long int moduleSize; readSize = read(fd, &(module->moduleHeader), sizeof(module->moduleHeader)); moduleSize = (long long) module->moduleHeader.moduleInfo.st_size; module->moduleData = malloc(moduleSize); readSize = read(fd, module->moduleData, moduleSize); return readSize; } // Put a module header into a HeaderStruct and read (skip) module data // Returns size of data read when reading a module header int WriteSingleModule(int fd, ModuleStruct* module, char* filename) { int writeSize; long long int moduleSize; moduleSize = (long long) module->moduleHeader.moduleInfo.st_size; module->moduleData = malloc(moduleSize); int fdInput = open(filename, O_RDONLY); if (fdInput < 0) return 0; read(fdInput, module->moduleData, moduleSize); close(fdInput); writeSize = write(fd, &(module->moduleHeader), sizeof(module->moduleHeader)); writeSize = write(fd, module->moduleData, moduleSize); return writeSize; } // Checks if operation went ok, if not then prints message and exits void SafetyCheck(int status, char* message) { if (status) { fprintf(stderr, "%s\n", message); exit(1); } return; } // Strip path from filename for adding to archive char* StripFilename(char* filename) { int nameStartPosition = -1; for (int i = 0; i < strlen(filename); i++) if (filename[i] == '/') nameStartPosition = i+1; if (nameStartPosition == -1) nameStartPosition = 0; int copySize = strlen(filename) - nameStartPosition; char* newFilename = malloc(copySize + 1); strncpy(newFilename, &filename[nameStartPosition], copySize); strcat(newFilename, "\0"); return newFilename; } // Overhead function for archive operations void Stuffy(int argc, char* argv[]) { int archiveAction = StuffyArgument(argc, argv); if (archiveAction < 0) { fprintf(stderr, "Usage: stuffy.out [OPTION] [ARCHIVE] [FILE]"); exit(1); } StuffyAction(argv, archiveAction); return; } // Checks for argument, if argument is found then returns argument number. // Returns -1 if not found int StuffyArgument(int argc, char* argv[]) { for (int i = 1; i < argc; i++) { if ((argv[i][0] == '-') && (argv[i][1] == 'a')) return 0; if ((argv[i][0] == '-') && (argv[i][1] == 'r')) return 1; if ((argv[i][0] == '-') && (argv[i][1] == 'l')) return 2; if ((argv[i][0] == '-') && (argv[i][1] == 'e')) return 3; } return -1; } // Redirects program to necessary action function void StuffyAction(char* argv[], int archiveAction) { if (archiveAction == 0) AddToArchive(argv[2], argv[3]); if (archiveAction == 1) RemoveFromArchive(argv[2], argv[3]); if (archiveAction == 2) ListArchive(argv[2]); if (archiveAction == 3) ExtractArchive(argv); return; } // Checks if filename is found in a header of archive int IsFileArchived(char* archiveName, char* filename) { ModuleStruct module; ssize_t readSize; char* newFilename = StripFilename(filename); int archiveFile = open(archiveName, O_RDONLY | O_CREAT, 0644); SafetyCheck((archiveFile < 0), "Archive failed to open."); do { readSize = ReadSingleModule(archiveFile, &(module)); free(module.moduleData); if (strcmp(module.moduleHeader.moduleName, filename) == 0) { free(newFilename); close(archiveFile); return 1; } } while (readSize > 0); free(newFilename); close(archiveFile); return 0; } // Check through archive for file, if in archive then inform user // Adds file to archive and can be repeatedly used to add more to the archive // If file is already in archive, then exit, let user know, and suggest removing // file already inside the archive void AddToArchive(char* archiveName, char* filename) { char* filenameCleaned = StripFilename(filename); if (IsFileArchived(archiveName, filenameCleaned)) { printf("File already exists in archive, try removing file first."); return; } if (access(filename, F_OK)) { printf("%s not found.", filename); return; } int archiveFile = open(archiveName, O_RDWR | O_CREAT, 0644); SafetyCheck((archiveFile < 0), "Archive failed to open."); ssize_t readSize; ModuleStruct module; do readSize = ReadSingleModule(archiveFile, &(module)); while (readSize > 0); strcpy(module.moduleHeader.moduleName, filenameCleaned); stat(filename, &(module.moduleHeader.moduleInfo)); WriteSingleModule(archiveFile, &module, filename); free(filenameCleaned); free(module.moduleData); return; } // Check through archive for file, if file exists with name, remove it // If file not in archive, print "somefile was not found." void RemoveFromArchive(char* archiveName, char* filename) { ssize_t readSize; long long int moduleSize; char* newFileName; strcpy(newFileName, filename); strcat(newFileName, ".tmp"); int archiveFile = open(archiveName, O_RDWR | O_CREAT, 0644); SafetyCheck((archiveFile < 0), "Archive failed to open."); SafetyCheck(IsFileArchived(archiveName, filename), strcat("Failed to find ", newFileName)); ModuleStruct module; int newArchiveFile = open(newFileName, O_WRONLY | O_CREAT, 0644); SafetyCheck((newArchiveFile < 0), "New archive failed to open."); do { readSize = ReadSingleModule(archiveFile, &(module)); write(newArchiveFile, &module.moduleHeader, sizeof(module.moduleHeader)); write(newArchiveFile, &module.moduleData, moduleSize); } while (readSize > 0); close(archiveFile); close(newArchiveFile); SafetyCheck(remove(archiveName), "Old archive failed removal."); SafetyCheck(rename(newFileName, archiveName), "New archive failed name change."); return; } // List names and sizes of files stored in archive // Last line prints total size of all files in archive void ListArchive(char* archiveName) { int archiveFile = open(archiveName, O_RDONLY); ssize_t readSize; SafetyCheck((archiveFile < 0), "Archive failed to open."); ModuleStruct module; readSize = ReadSingleModule(archiveFile, &module); while (readSize > 0) { printf("Name: %s | Size: %ld\n", module.moduleHeader.moduleName, module.moduleHeader.moduleInfo.st_size); readSize = ReadSingleModule(archiveFile, &module); } return; } int Test_ListArchive(char* archiveName) { struct stat statArchive; int archiveFile = open(archiveName, O_RDONLY); ssize_t readSize; long int sizeTotal = 0; if (archiveFile < 0) return 0; ModuleStruct module; stat(archiveName, &statArchive); do { readSize = ReadSingleModule(archiveFile, &module); if (readSize > 0) { sizeTotal += sizeof(module.moduleHeader); sizeTotal += module.moduleHeader.moduleInfo.st_size; } } while (readSize > 0); return (statArchive.st_size == sizeTotal); } // Extract data of name file from archive to stdout, which is then redirected // Extracted data remains in archive void ExtractArchive(char* argv[]) { printf("'ExtractArchive()' function is still broken.\n"); return; }