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