heloooo, youuhouuu
This commit is contained in:
commit
def6ecb013
10 changed files with 434 additions and 0 deletions
34
epitar/Makefile
Normal file
34
epitar/Makefile
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -std=c99 -pedantic -Werror -Wall -Wextra -Wvla
|
||||||
|
LDFLAGS=
|
||||||
|
|
||||||
|
DBG_CFLAGS = -fsanitize=address -g
|
||||||
|
DBG_LDFLAGS= -fsanitize=address
|
||||||
|
|
||||||
|
|
||||||
|
SRC_DIR = src
|
||||||
|
LIB_SRCS =
|
||||||
|
MAIN_SRCS = main.c
|
||||||
|
|
||||||
|
# SRCS = $(patsubst %,$(SRC_DIR)/%, $(MAIN_SRCS))
|
||||||
|
SRCS = $(MAIN_SRCS:%=$(SRC_DIR)/%) $(LIB_SRCS:%=$(SRC_DIR)/%)
|
||||||
|
OBJS = $(SRCS:.c=.o)
|
||||||
|
|
||||||
|
TARGET= epitar
|
||||||
|
# DBG_TARGET = epitar-dbg
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
|
||||||
|
@echo $(OBJS)
|
||||||
|
|
||||||
|
debug: CFLAGS += $(DBG_CFLAGS)
|
||||||
|
debug: LDFLAGS += $(DBG_LDFLAGS)
|
||||||
|
debug: $(OBJS)
|
||||||
|
$(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS)
|
||||||
|
|
||||||
|
check:
|
||||||
|
dash ./tests/run.sh
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(TARGET)
|
||||||
|
$(RM) $(OBJS)
|
||||||
9
epitar/src/archive.h
Normal file
9
epitar/src/archive.h
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef ARCHIVE_H
|
||||||
|
#define ARCHIVE_H
|
||||||
|
|
||||||
|
/* @brief Archives the listed `files` into `archive_name`
|
||||||
|
* @return 0 on success, the corresponding error code otherwise
|
||||||
|
*/
|
||||||
|
int archive(char *archive_name, char **files);
|
||||||
|
|
||||||
|
#endif // ARCHIVE_H
|
||||||
140
epitar/src/config.c
Normal file
140
epitar/src/config.c
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static void print_files_array(char **input_files)
|
||||||
|
{
|
||||||
|
while (*input_files != NULL)
|
||||||
|
{
|
||||||
|
printf(" - ");
|
||||||
|
puts(*input_files);
|
||||||
|
input_files++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the corresponding ARG_* macro
|
||||||
|
static int handle_opt(char **argv, char opt, struct config *cfg)
|
||||||
|
{
|
||||||
|
// Options without value
|
||||||
|
// Help
|
||||||
|
if (opt == 'h')
|
||||||
|
return ARG_HELP;
|
||||||
|
|
||||||
|
// Options with value
|
||||||
|
|
||||||
|
if (optarg == NULL)
|
||||||
|
return ARG_INVALID;
|
||||||
|
|
||||||
|
switch (opt)
|
||||||
|
{
|
||||||
|
// Archive mode
|
||||||
|
case 'c':
|
||||||
|
if (cfg->mode != UNDEFINED)
|
||||||
|
return ARG_INVALID;
|
||||||
|
cfg->mode = ARCHIVE;
|
||||||
|
return ARG_ARCHIVE;
|
||||||
|
|
||||||
|
// Extract mode
|
||||||
|
case 'x':
|
||||||
|
if (cfg->mode != UNDEFINED)
|
||||||
|
return ARG_INVALID;
|
||||||
|
cfg->mode = EXTRACT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ARG_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ARG_VALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if config is valid, false otherwise
|
||||||
|
static bool check_config(struct config *cfg)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int args_handler(int argc, char **argv, struct config *config)
|
||||||
|
{
|
||||||
|
struct option options[] = { // Global
|
||||||
|
{ "archive", required_argument, NULL, 'c' },
|
||||||
|
{ "extract", required_argument, NULL, 'x' },
|
||||||
|
{ "verbose", no_argument, NULL, 'v' },
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
// End
|
||||||
|
{ NULL, 0, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
config = calloc(1, sizeof(struct config));
|
||||||
|
|
||||||
|
char opt;
|
||||||
|
int optindex = 0;
|
||||||
|
while ((opt = getopt_long(argc, argv, "cxvh", options, &optindex)) != -1)
|
||||||
|
{
|
||||||
|
int err = handle_opt(argv, opt, config);
|
||||||
|
switch (err)
|
||||||
|
{
|
||||||
|
case ARG_VALID:
|
||||||
|
if (check_config(config))
|
||||||
|
return ARG_VALID;
|
||||||
|
config_destroy(config);
|
||||||
|
return ARG_INVALID;
|
||||||
|
|
||||||
|
case ARG_HELP:
|
||||||
|
print_usage();
|
||||||
|
config_destroy(config);
|
||||||
|
return ARG_HELP;
|
||||||
|
|
||||||
|
default:
|
||||||
|
print_usage();
|
||||||
|
config_destroy(config);
|
||||||
|
return ARG_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_config(struct config *config)
|
||||||
|
{
|
||||||
|
printf("Mode: %s\n",
|
||||||
|
config->mode == EXTRACT ? "EXTRACT"
|
||||||
|
: config->mode == ARCHIVE ? "ARCHIVE"
|
||||||
|
: "UNDEFINED");
|
||||||
|
|
||||||
|
printf("Input file(s):\n");
|
||||||
|
if (config->input_files)
|
||||||
|
print_files_array(config->input_files);
|
||||||
|
else
|
||||||
|
puts("-> NULL");
|
||||||
|
|
||||||
|
printf("Verbose: %B\n", config->verbose);
|
||||||
|
printf("Show help message: %B\n", config->show_help);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_usage(void)
|
||||||
|
{
|
||||||
|
puts("Usage: epitar -[xcvh] <file.tar> [<files>]");
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_invalid_option(void)
|
||||||
|
{
|
||||||
|
puts("epitar: invalid or missing option");
|
||||||
|
puts("Try './epitar -h' for more information");
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_destroy(struct config *config)
|
||||||
|
{
|
||||||
|
char **current_str = config->input_files;
|
||||||
|
while (current_str != NULL && *current_str != NULL)
|
||||||
|
{
|
||||||
|
free(*current_str);
|
||||||
|
current_str++;
|
||||||
|
}
|
||||||
|
free(config->input_files);
|
||||||
|
free(config);
|
||||||
|
}
|
||||||
56
epitar/src/config.h
Normal file
56
epitar/src/config.h
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#ifndef ARGS_H
|
||||||
|
#define ARGS_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define ARG_VALID 0
|
||||||
|
#define ARG_INVALID 1
|
||||||
|
#define ARG_HELP 2
|
||||||
|
#define ARG_ARCHIVE 3
|
||||||
|
|
||||||
|
enum tar_mode
|
||||||
|
{
|
||||||
|
UNDEFINED,
|
||||||
|
EXTRACT,
|
||||||
|
ARCHIVE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config
|
||||||
|
{
|
||||||
|
/* Defines what action the program will perform */
|
||||||
|
enum tar_mode mode;
|
||||||
|
/* File(s) to archive/extract */
|
||||||
|
char **input_files;
|
||||||
|
/* Program output after archiving */
|
||||||
|
char *output_file;
|
||||||
|
/* Enable or disable verbose mode */
|
||||||
|
bool verbose;
|
||||||
|
/* Show the help message */
|
||||||
|
bool show_help;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles command-line arguments and populates the args_options structure.
|
||||||
|
* @param argc The argument count.
|
||||||
|
* @param argv The argument vector.
|
||||||
|
* @param config Pointer to config structure populate.
|
||||||
|
* This function will handle the memory allocation.
|
||||||
|
* @return 0 on success, non-zero on failure.
|
||||||
|
*/
|
||||||
|
int args_handler(int argc, char **argv, struct config *config);
|
||||||
|
|
||||||
|
/** Prints the parsed arguments for debugging purposes.
|
||||||
|
* @param options Pointer to args_options structure containing parsed options.
|
||||||
|
*/
|
||||||
|
void print_config(struct config *config);
|
||||||
|
|
||||||
|
/* Prints the usage information for the program.
|
||||||
|
*/
|
||||||
|
void print_usage(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
void config_destroy(struct config *config);
|
||||||
|
|
||||||
|
#endif /* ARGS_H */
|
||||||
9
epitar/src/extract.h
Normal file
9
epitar/src/extract.h
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef EXTRACT_H
|
||||||
|
#define EXTRACT_H
|
||||||
|
|
||||||
|
/* @brief Extract and write files from `archive_name`
|
||||||
|
* @return 0 on success, the corresponding error code otherwise
|
||||||
|
*/
|
||||||
|
int extract(char *archive_name);
|
||||||
|
|
||||||
|
#endif // EXTRACT_H
|
||||||
1
epitar/src/main.c
Normal file
1
epitar/src/main.c
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
59
epitar/src/tar.c
Normal file
59
epitar/src/tar.c
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
#include "tar.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct unixtar_header *get_unixtar_header(union tar_header *header)
|
||||||
|
{
|
||||||
|
if (header == NULL)
|
||||||
|
return NULL;
|
||||||
|
char empty_magic[6] = { 0 };
|
||||||
|
if (memcmp(empty_magic, header->ustar.magic, 6) != 0)
|
||||||
|
return &header->unixtar;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ustar_header *get_ustar_header(union tar_header *header)
|
||||||
|
{
|
||||||
|
if (header == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (strcmp(header->ustar.magic, USTAR_MAGIC) == 0)
|
||||||
|
return &header->ustar;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_checksum(union tar_header *header)
|
||||||
|
{
|
||||||
|
struct ustar_header *ustar_header;
|
||||||
|
struct unixtar_header *unixtar_header;
|
||||||
|
int actual_checksum;
|
||||||
|
|
||||||
|
// USTAR
|
||||||
|
if ((ustar_header = get_ustar_header(header)) != NULL)
|
||||||
|
{
|
||||||
|
actual_checksum = atoi(ustar_header->chksum);
|
||||||
|
}
|
||||||
|
// UNIXTAR
|
||||||
|
else if ((unixtar_header = get_unixtar_header(header)) != NULL)
|
||||||
|
{
|
||||||
|
actual_checksum = atoi(unixtar_header->chksum);
|
||||||
|
}
|
||||||
|
// Unsupported format
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int computed_checksum = compute_checksum(header);
|
||||||
|
return computed_checksum == actual_checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
int compute_checksum(union tar_header *header)
|
||||||
|
{
|
||||||
|
char *block = header->raw_block;
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||||
|
sum += block[i];
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
117
epitar/src/tar.h
Normal file
117
epitar/src/tar.h
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
#ifndef TAR_H
|
||||||
|
#define TAR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// === Definitions
|
||||||
|
|
||||||
|
#define BLOCK_SIZE 512
|
||||||
|
|
||||||
|
#define USTAR_MAGIC "ustar" /* ustar and a null */
|
||||||
|
#define UNIXTAR_MAGIC ""
|
||||||
|
#define TMAGLEN 6
|
||||||
|
|
||||||
|
#define TVERSION "00" /* 00 and no null */
|
||||||
|
#define TVERSLEN 2
|
||||||
|
|
||||||
|
// Values for the typeflag field
|
||||||
|
#define REGTYPE '0' /* regular file */
|
||||||
|
#define AREGTYPE '\0' /* regular file */
|
||||||
|
#define LNKTYPE '1' /* link */
|
||||||
|
#define SYMTYPE '2' /* reserved */
|
||||||
|
#define CHRTYPE '3' /* character special */
|
||||||
|
#define BLKTYPE '4' /* block special */
|
||||||
|
#define DIRTYPE '5' /* directory */
|
||||||
|
#define FIFOTYPE '6' /* FIFO special */
|
||||||
|
#define CONTTYPE '7' /* reserved */
|
||||||
|
|
||||||
|
// Bit masks for the mpde field
|
||||||
|
#define TSUID 04000 /* set UID on execution */
|
||||||
|
#define TSGID 02000 /* set GID on execution */
|
||||||
|
#define TSVTX 01000 /* reserved */
|
||||||
|
// File permissions
|
||||||
|
#define TUREAD 00400 /* read by owner */
|
||||||
|
#define TUWRITE 00200 /* write by owner */
|
||||||
|
#define TUEXEC 00100 /* execute/search by owner */
|
||||||
|
#define TGREAD 00040 /* read by group */
|
||||||
|
#define TGWRITE 00020 /* write by group */
|
||||||
|
#define TGEXEC 00010 /* execute/search by group */
|
||||||
|
#define TOREAD 00004 /* read by other */
|
||||||
|
#define TOWRITE 00002 /* write by other */
|
||||||
|
#define TOEXEC 00001 /* execute/search by other */
|
||||||
|
|
||||||
|
// === Structures
|
||||||
|
|
||||||
|
enum error_codes
|
||||||
|
{
|
||||||
|
SUCCESS = 0,
|
||||||
|
UNKNOWN_ERROR,
|
||||||
|
FILE_NOT_FOUND,
|
||||||
|
BAD_CHECKSUM,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ustar_header
|
||||||
|
{
|
||||||
|
char name[100];
|
||||||
|
char mode[8];
|
||||||
|
char uid[8];
|
||||||
|
char gid[8];
|
||||||
|
char size[12];
|
||||||
|
char mtime[12];
|
||||||
|
char chksum[8];
|
||||||
|
char typeflag;
|
||||||
|
char linkname[100];
|
||||||
|
char magic[6];
|
||||||
|
char version[2];
|
||||||
|
char uname[32];
|
||||||
|
char gname[32];
|
||||||
|
char devmajor[8];
|
||||||
|
char devminor[8];
|
||||||
|
char prefix[155];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct unixtar_header
|
||||||
|
{
|
||||||
|
char name[100];
|
||||||
|
char mode[8];
|
||||||
|
char uid[8];
|
||||||
|
char gid[8];
|
||||||
|
char size[12];
|
||||||
|
char mtime[12];
|
||||||
|
char chksum[8];
|
||||||
|
char link[1];
|
||||||
|
char linkname[100];
|
||||||
|
char padding[255]; // Should be empty
|
||||||
|
};
|
||||||
|
|
||||||
|
union tar_header
|
||||||
|
{
|
||||||
|
struct unixtar_header unixtar;
|
||||||
|
struct ustar_header ustar;
|
||||||
|
char raw_block[512];
|
||||||
|
};
|
||||||
|
|
||||||
|
// === Functions
|
||||||
|
|
||||||
|
/* @brief Returns the header in the unix tar format
|
||||||
|
* @return the header if header is indeed in the unix tar format, NULL otherwise
|
||||||
|
*/
|
||||||
|
struct unixtar_header *get_unixtar_header(union tar_header *header);
|
||||||
|
|
||||||
|
/* @brief Returns the header in the posix (ustar) tar format
|
||||||
|
* @return the header if header is indeed in the posix tar format, NULL
|
||||||
|
* otherwise
|
||||||
|
*/
|
||||||
|
struct ustar_header *get_ustar_header(union tar_header *header);
|
||||||
|
|
||||||
|
/* @brief checks if file has not been corrupted via checksum
|
||||||
|
* @return true if member file is valid, false otherwise
|
||||||
|
*/
|
||||||
|
bool check_checksum(union tar_header *header);
|
||||||
|
|
||||||
|
/* @brief computes the checksum of the given file
|
||||||
|
* @return the checksum
|
||||||
|
*/
|
||||||
|
int compute_checksum(union tar_header *header);
|
||||||
|
|
||||||
|
#endif // TAR_H
|
||||||
3
epitar/src/utils.c
Normal file
3
epitar/src/utils.c
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
6
epitar/src/utils.h
Normal file
6
epitar/src/utils.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef UTILS_H
|
||||||
|
#define UTILS_H
|
||||||
|
|
||||||
|
void print_str_array(const char **input_files);
|
||||||
|
|
||||||
|
#endif /* UTILS_H */
|
||||||
Loading…
Add table
Add a link
Reference in a new issue