heloooo, youuhouuu

This commit is contained in:
Gu://em_ 2026-04-06 20:07:49 +02:00
commit def6ecb013
10 changed files with 434 additions and 0 deletions

34
epitar/Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1 @@

59
epitar/src/tar.c Normal file
View 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
View 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
View file

@ -0,0 +1,3 @@
#include "utils.h"
#include <stdio.h>

6
epitar/src/utils.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef UTILS_H
#define UTILS_H
void print_str_array(const char **input_files);
#endif /* UTILS_H */