#include #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 ReadSingleModuleFromArchive(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; } // Write a single module into file int WriteSingleModuleToArchive(int fd, ModuleStruct* module) { int writeSize; long long int moduleSize; moduleSize = (long long) module->moduleHeader.moduleInfo.st_size; writeSize = write(fd, &(module->moduleHeader), sizeof(module->moduleHeader)); writeSize = write(fd, module->moduleData, moduleSize); return writeSize; } void PrintModuleHeader(ModuleStruct* module) { printf("Name: %s | ", module->moduleHeader.moduleName); printf("Size: %ld\n", module->moduleHeader.moduleInfo.st_size); return; } int OpenArchive(char* archiveName, int flags) { int archiveFD = open(archiveName, flags, 0644); if (archiveFD < 0) { perror("Archive"); return -1; } return archiveFD; } void LoadModuleFromFile(char* filename, ModuleStruct* module) { stat(filename, &(module->moduleHeader.moduleInfo)); long long int moduleSize; moduleSize = (long long) module->moduleHeader.moduleInfo.st_size; module->moduleData = malloc(moduleSize); int fdInput = open(filename, O_RDONLY); read(fdInput, module->moduleData, moduleSize); close(fdInput); return; } // 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(argc, 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(int argc, 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(argc, 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 archiveFD = OpenArchive(archiveName, O_RDONLY | O_CREAT); do { readSize = ReadSingleModuleFromArchive(archiveFD, &(module)); free(module.moduleData); if (strcmp(module.moduleHeader.moduleName, newFilename) == 0) { free(newFilename); close(archiveFD); return 1; } } while (readSize > 0); free(newFilename); close(archiveFD); 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) { ModuleStruct module; ssize_t readSize; char* filenameCleaned = StripFilename(filename); if (IsFileArchived(archiveName, filenameCleaned)) { fprintf(stderr, "File already exists in archive, try removing file first.\n"); return; } if (access(filename, F_OK)) { fprintf(stderr, "%s not found.\n", filename); return; } int archiveFD = OpenArchive(archiveName, O_WRONLY | O_APPEND| O_CREAT); LoadModuleFromFile(filename, &module); strcpy(module.moduleHeader.moduleName, filenameCleaned); WriteSingleModuleToArchive(archiveFD, &module); free(filenameCleaned); free(module.moduleData); close(archiveFD); 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; char* filenameCleaned = StripFilename(filename); char tempArchiveName[strlen(archiveName)+5]; strcpy(tempArchiveName, archiveName); strcat(tempArchiveName, ".tmp\0"); int archiveFile = open(archiveName, O_RDWR | O_CREAT, 0644); SafetyCheck((archiveFile < 0), "Archive failed to open."); if (!IsFileArchived(archiveName, filenameCleaned)) { fprintf(stderr, "Failed to find %s\n", filenameCleaned); return; } ModuleStruct module; int newArchiveFD = OpenArchive(tempArchiveName, O_WRONLY | O_CREAT); readSize = ReadSingleModuleFromArchive(archiveFile, &(module)); while (readSize > 0) { if (strcmp(module.moduleHeader.moduleName, filenameCleaned) != 0) WriteSingleModuleToArchive(newArchiveFD, &module); free(module.moduleData); readSize = ReadSingleModuleFromArchive(archiveFile, &(module)); } close(archiveFile); close(newArchiveFD); SafetyCheck(remove(archiveName), "Old archive failed removal."); SafetyCheck(rename(tempArchiveName, archiveName), "New archive failed name change."); free(filenameCleaned); 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; do { readSize = ReadSingleModuleFromArchive(archiveFile, &module); if (readSize > 0) { PrintModuleHeader(&module); free(module.moduleData); } } while (readSize > 0); return; } int Test_ListArchive(char* archiveName) { struct stat statArchive; int archiveFD = OpenArchive(archiveName, O_RDONLY); ssize_t readSize; long int sizeTotal = 0; if (archiveFD < 0) return -1; ModuleStruct module; stat(archiveName, &statArchive); do { readSize = ReadSingleModuleFromArchive(archiveFD, &module); if (readSize > 0) { sizeTotal += sizeof(module.moduleHeader); sizeTotal += module.moduleHeader.moduleInfo.st_size; } free(module.moduleData); } while (readSize > 0); return sizeTotal; } // Extract data of name file from archive to stdout, which is then redirected // Extracted data remains in archive int _ExtractArchive(char* archiveName, char* filenameIn) { ssize_t readSize; ssize_t writeSize = 0; long long int moduleSize; char* filenameCleaned = StripFilename(filenameIn); int archiveFile = open(archiveName, O_RDWR | O_CREAT, 0644); if (!IsFileArchived(archiveName, filenameCleaned)) { fprintf(stderr, "Failed to find %s\n", filenameCleaned); return -1; } ModuleStruct module; readSize = ReadSingleModuleFromArchive(archiveFile, &(module)); while (readSize > 0) { if (strcmp(module.moduleHeader.moduleName, filenameCleaned) == 0) writeSize += write(STDOUT_FILENO, module.moduleData, module.moduleHeader.moduleInfo.st_size); free(module.moduleData); readSize = ReadSingleModuleFromArchive(archiveFile, &(module)); } close(archiveFile); free(filenameCleaned); return writeSize; } void ExtractArchive(int argc, char* argv[]) { int writeSize; writeSize = _ExtractArchive(argv[2], argv[3]); return; }