2022-11-08 20:37:57 -06:00
|
|
|
#include <fcntl.h>
|
2022-11-02 15:29:00 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2022-11-08 20:37:57 -06:00
|
|
|
#include <string.h>
|
2022-11-02 15:29:00 -05:00
|
|
|
#include <unistd.h>
|
2022-11-08 20:37:57 -06:00
|
|
|
#include <sys/types.h>
|
2022-11-11 00:29:37 -06:00
|
|
|
#include <sys/wait.h>
|
2022-11-02 15:29:00 -05:00
|
|
|
#include "stuffy.h"
|
|
|
|
|
2022-11-10 18:30:35 -06:00
|
|
|
// Put a module header into a HeaderStruct and read (skip) module data
|
|
|
|
// Returns size of data read when reading a module header
|
2022-11-12 01:25:08 -06:00
|
|
|
int ReadSingleModuleFromArchive(int fd, ModuleStruct* module)
|
2022-11-10 18:30:35 -06:00
|
|
|
{
|
|
|
|
int readSize;
|
|
|
|
long long int moduleSize;
|
2022-11-10 19:58:59 -06:00
|
|
|
readSize = read(fd, &(module->moduleHeader), sizeof(module->moduleHeader));
|
2022-11-10 18:30:35 -06:00
|
|
|
moduleSize = (long long) module->moduleHeader.moduleInfo.st_size;
|
|
|
|
module->moduleData = malloc(moduleSize);
|
2022-11-10 19:58:59 -06:00
|
|
|
readSize = read(fd, module->moduleData, moduleSize);
|
|
|
|
return readSize;
|
|
|
|
}
|
|
|
|
|
2022-11-10 23:52:54 -06:00
|
|
|
// Write a single module into file
|
2022-11-12 01:25:08 -06:00
|
|
|
int WriteSingleModuleToArchive(int fd, ModuleStruct* module)
|
2022-11-10 19:58:59 -06:00
|
|
|
{
|
2022-11-10 21:36:19 -06:00
|
|
|
int writeSize;
|
2022-11-10 19:58:59 -06:00
|
|
|
long long int moduleSize;
|
|
|
|
moduleSize = (long long) module->moduleHeader.moduleInfo.st_size;
|
2022-11-10 21:36:19 -06:00
|
|
|
writeSize = write(fd, &(module->moduleHeader), sizeof(module->moduleHeader));
|
|
|
|
writeSize = write(fd, module->moduleData, moduleSize);
|
|
|
|
return writeSize;
|
2022-11-10 18:30:35 -06:00
|
|
|
}
|
|
|
|
|
2022-11-12 01:25:08 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-11-10 18:30:35 -06:00
|
|
|
// 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
|
2022-11-02 15:29:00 -05:00
|
|
|
void Stuffy(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
int archiveAction = StuffyArgument(argc, argv);
|
|
|
|
if (archiveAction < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Usage: stuffy.out [OPTION] [ARCHIVE] [FILE]");
|
|
|
|
exit(1);
|
|
|
|
}
|
2022-11-10 23:52:54 -06:00
|
|
|
StuffyAction(argc, argv, archiveAction);
|
2022-11-02 15:29:00 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-10 18:30:35 -06:00
|
|
|
// Checks for argument, if argument is found then returns argument number.
|
|
|
|
// Returns -1 if not found
|
2022-11-02 15:29:00 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-11-10 18:30:35 -06:00
|
|
|
// Redirects program to necessary action function
|
2022-11-10 23:52:54 -06:00
|
|
|
void StuffyAction(int argc, char* argv[], int archiveAction)
|
2022-11-02 15:29:00 -05:00
|
|
|
{
|
2022-11-08 20:37:57 -06:00
|
|
|
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)
|
2022-11-10 23:52:54 -06:00
|
|
|
ExtractArchive(argc, argv);
|
2022-11-10 22:10:49 -06:00
|
|
|
return;
|
2022-11-08 20:37:57 -06:00
|
|
|
}
|
|
|
|
|
2022-11-10 18:30:35 -06:00
|
|
|
// Checks if filename is found in a header of archive
|
|
|
|
int IsFileArchived(char* archiveName, char* filename)
|
2022-11-08 20:37:57 -06:00
|
|
|
{
|
2022-11-10 18:30:35 -06:00
|
|
|
ModuleStruct module;
|
|
|
|
ssize_t readSize;
|
|
|
|
char* newFilename = StripFilename(filename);
|
2022-11-12 01:25:08 -06:00
|
|
|
int archiveFD = OpenArchive(archiveName, O_RDONLY | O_CREAT);
|
2022-11-10 18:30:35 -06:00
|
|
|
do
|
2022-11-08 20:37:57 -06:00
|
|
|
{
|
2022-11-12 01:25:08 -06:00
|
|
|
readSize = ReadSingleModuleFromArchive(archiveFD, &(module));
|
2022-11-10 18:30:35 -06:00
|
|
|
free(module.moduleData);
|
2022-11-13 17:45:17 -06:00
|
|
|
if (strcmp(module.moduleHeader.moduleName, newFilename) == 0)
|
2022-11-10 18:30:35 -06:00
|
|
|
{
|
|
|
|
free(newFilename);
|
2022-11-12 01:25:08 -06:00
|
|
|
close(archiveFD);
|
2022-11-08 20:37:57 -06:00
|
|
|
return 1;
|
2022-11-10 18:30:35 -06:00
|
|
|
}
|
|
|
|
} while (readSize > 0);
|
|
|
|
free(newFilename);
|
2022-11-12 01:25:08 -06:00
|
|
|
close(archiveFD);
|
2022-11-08 20:37:57 -06:00
|
|
|
return 0;
|
2022-11-02 15:29:00 -05:00
|
|
|
}
|
|
|
|
|
2022-11-10 18:30:35 -06:00
|
|
|
// 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)
|
2022-11-02 15:29:00 -05:00
|
|
|
{
|
2022-11-12 01:25:08 -06:00
|
|
|
ModuleStruct module;
|
|
|
|
ssize_t readSize;
|
2022-11-10 22:10:49 -06:00
|
|
|
char* filenameCleaned = StripFilename(filename);
|
|
|
|
if (IsFileArchived(archiveName, filenameCleaned))
|
|
|
|
{
|
2022-11-10 23:52:54 -06:00
|
|
|
fprintf(stderr, "File already exists in archive, try removing file first.\n");
|
2022-11-10 22:10:49 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (access(filename, F_OK))
|
|
|
|
{
|
2022-11-10 23:52:54 -06:00
|
|
|
fprintf(stderr, "%s not found.\n", filename);
|
2022-11-10 22:10:49 -06:00
|
|
|
return;
|
|
|
|
}
|
2022-11-13 16:52:04 -06:00
|
|
|
int archiveFD = OpenArchive(archiveName, O_WRONLY | O_APPEND| O_CREAT);
|
2022-11-12 01:25:08 -06:00
|
|
|
LoadModuleFromFile(filename, &module);
|
2022-11-10 21:36:19 -06:00
|
|
|
strcpy(module.moduleHeader.moduleName, filenameCleaned);
|
2022-11-12 01:25:08 -06:00
|
|
|
WriteSingleModuleToArchive(archiveFD, &module);
|
2022-11-10 21:36:19 -06:00
|
|
|
free(filenameCleaned);
|
2022-11-10 18:30:35 -06:00
|
|
|
free(module.moduleData);
|
2022-11-12 01:25:08 -06:00
|
|
|
close(archiveFD);
|
2022-11-10 21:36:19 -06:00
|
|
|
return;
|
2022-11-02 15:29:00 -05:00
|
|
|
}
|
|
|
|
|
2022-11-10 18:30:35 -06:00
|
|
|
// 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)
|
2022-11-02 15:29:00 -05:00
|
|
|
{
|
2022-11-08 21:22:07 -06:00
|
|
|
ssize_t readSize;
|
2022-11-10 23:52:54 -06:00
|
|
|
char* filenameCleaned = StripFilename(filename);
|
|
|
|
char tempArchiveName[strlen(archiveName)+5];
|
|
|
|
strcpy(tempArchiveName, archiveName);
|
|
|
|
strcat(tempArchiveName, ".tmp\0");
|
2022-11-08 21:22:07 -06:00
|
|
|
int archiveFile = open(archiveName, O_RDWR | O_CREAT, 0644);
|
2022-11-10 18:30:35 -06:00
|
|
|
SafetyCheck((archiveFile < 0), "Archive failed to open.");
|
2022-11-10 23:52:54 -06:00
|
|
|
if (!IsFileArchived(archiveName, filenameCleaned))
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Failed to find %s\n", filenameCleaned);
|
|
|
|
return;
|
|
|
|
}
|
2022-11-10 18:30:35 -06:00
|
|
|
ModuleStruct module;
|
2022-11-12 01:25:08 -06:00
|
|
|
int newArchiveFD = OpenArchive(tempArchiveName, O_WRONLY | O_CREAT);
|
|
|
|
readSize = ReadSingleModuleFromArchive(archiveFile, &(module));
|
2022-11-10 23:52:54 -06:00
|
|
|
while (readSize > 0)
|
2022-11-08 21:22:07 -06:00
|
|
|
{
|
2022-11-10 23:52:54 -06:00
|
|
|
if (strcmp(module.moduleHeader.moduleName, filenameCleaned) != 0)
|
2022-11-12 01:25:08 -06:00
|
|
|
WriteSingleModuleToArchive(newArchiveFD, &module);
|
2022-11-11 00:29:37 -06:00
|
|
|
free(module.moduleData);
|
2022-11-12 01:25:08 -06:00
|
|
|
readSize = ReadSingleModuleFromArchive(archiveFile, &(module));
|
2022-11-08 21:22:07 -06:00
|
|
|
}
|
2022-11-10 18:30:35 -06:00
|
|
|
close(archiveFile);
|
2022-11-12 01:25:08 -06:00
|
|
|
close(newArchiveFD);
|
2022-11-10 18:30:35 -06:00
|
|
|
SafetyCheck(remove(archiveName), "Old archive failed removal.");
|
2022-11-10 23:52:54 -06:00
|
|
|
SafetyCheck(rename(tempArchiveName, archiveName),
|
2022-11-10 18:30:35 -06:00
|
|
|
"New archive failed name change.");
|
2022-11-10 23:52:54 -06:00
|
|
|
free(filenameCleaned);
|
2022-11-08 21:22:07 -06:00
|
|
|
return;
|
2022-11-02 15:29:00 -05:00
|
|
|
}
|
|
|
|
|
2022-11-10 18:30:35 -06:00
|
|
|
// List names and sizes of files stored in archive
|
|
|
|
// Last line prints total size of all files in archive
|
2022-11-02 15:29:00 -05:00
|
|
|
void ListArchive(char* archiveName)
|
|
|
|
{
|
2022-11-08 20:37:57 -06:00
|
|
|
int archiveFile = open(archiveName, O_RDONLY);
|
|
|
|
ssize_t readSize;
|
2022-11-10 18:30:35 -06:00
|
|
|
SafetyCheck((archiveFile < 0), "Archive failed to open.");
|
2022-11-10 21:36:19 -06:00
|
|
|
ModuleStruct module;
|
2022-11-12 01:25:08 -06:00
|
|
|
do
|
2022-11-08 20:37:57 -06:00
|
|
|
{
|
2022-11-12 01:25:08 -06:00
|
|
|
readSize = ReadSingleModuleFromArchive(archiveFile, &module);
|
|
|
|
if (readSize > 0)
|
|
|
|
{
|
|
|
|
PrintModuleHeader(&module);
|
|
|
|
free(module.moduleData);
|
|
|
|
}
|
|
|
|
} while (readSize > 0);
|
2022-11-08 21:22:07 -06:00
|
|
|
return;
|
2022-11-02 15:29:00 -05:00
|
|
|
}
|
|
|
|
|
2022-11-10 21:36:19 -06:00
|
|
|
int Test_ListArchive(char* archiveName)
|
|
|
|
{
|
|
|
|
struct stat statArchive;
|
2022-11-12 01:25:08 -06:00
|
|
|
int archiveFD = OpenArchive(archiveName, O_RDONLY);
|
2022-11-10 21:36:19 -06:00
|
|
|
ssize_t readSize;
|
|
|
|
long int sizeTotal = 0;
|
2022-11-12 01:25:08 -06:00
|
|
|
if (archiveFD < 0)
|
2022-11-10 23:52:54 -06:00
|
|
|
return -1;
|
2022-11-10 21:36:19 -06:00
|
|
|
ModuleStruct module;
|
|
|
|
stat(archiveName, &statArchive);
|
|
|
|
do
|
|
|
|
{
|
2022-11-12 01:25:08 -06:00
|
|
|
readSize = ReadSingleModuleFromArchive(archiveFD, &module);
|
2022-11-10 21:36:19 -06:00
|
|
|
if (readSize > 0)
|
|
|
|
{
|
|
|
|
sizeTotal += sizeof(module.moduleHeader);
|
|
|
|
sizeTotal += module.moduleHeader.moduleInfo.st_size;
|
|
|
|
}
|
2022-11-11 00:29:37 -06:00
|
|
|
free(module.moduleData);
|
2022-11-12 01:25:08 -06:00
|
|
|
} while (readSize > 0);
|
2022-11-10 23:52:54 -06:00
|
|
|
return sizeTotal;
|
2022-11-10 21:36:19 -06:00
|
|
|
}
|
|
|
|
|
2022-11-10 18:30:35 -06:00
|
|
|
// Extract data of name file from archive to stdout, which is then redirected
|
|
|
|
// Extracted data remains in archive
|
2022-11-11 00:29:37 -06:00
|
|
|
int _ExtractArchive(char* archiveName, char* filenameIn)
|
2022-11-02 15:29:00 -05:00
|
|
|
{
|
2022-11-10 23:52:54 -06:00
|
|
|
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;
|
2022-11-12 01:25:08 -06:00
|
|
|
readSize = ReadSingleModuleFromArchive(archiveFile, &(module));
|
2022-11-10 23:52:54 -06:00
|
|
|
while (readSize > 0)
|
|
|
|
{
|
|
|
|
if (strcmp(module.moduleHeader.moduleName, filenameCleaned) == 0)
|
2022-11-11 00:29:37 -06:00
|
|
|
writeSize += write(STDOUT_FILENO, module.moduleData, module.moduleHeader.moduleInfo.st_size);
|
|
|
|
free(module.moduleData);
|
2022-11-12 01:25:08 -06:00
|
|
|
readSize = ReadSingleModuleFromArchive(archiveFile, &(module));
|
2022-11-10 23:52:54 -06:00
|
|
|
}
|
|
|
|
close(archiveFile);
|
|
|
|
free(filenameCleaned);
|
|
|
|
return writeSize;
|
2022-11-02 15:29:00 -05:00
|
|
|
}
|
2022-11-10 23:52:54 -06:00
|
|
|
|
|
|
|
void ExtractArchive(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
int writeSize;
|
2022-11-11 00:29:37 -06:00
|
|
|
writeSize = _ExtractArchive(argv[2], argv[3]);
|
2022-11-10 23:52:54 -06:00
|
|
|
return;
|
2022-11-13 16:52:04 -06:00
|
|
|
}
|