In C I have created a program which can archive multiple files into an archive file via the command line.
e.g.
$echo 'file1/2' > file1/2.txt

$./archive file1.txt file2.txt arhivedfile

$cat archivedfile
file1
file2

how do I create a process so that in my archivedfile I have:
header
file1
end
header
file2
end


They are all stored in the archive file one after another after another. I know that perhaps a header file is needed(containing filename, size of filename, start and end of file) for extracting these files back out into their original form, but how would I go about doing this.

I am stuck on where and how to start
Please could someone help me on some logic as to how to approach extracting files back out of an archived file.

Recommended Answers

All 3 Replies

Program archive will most likely have to make two passes through each of the command line arguments. The first pass will collect a list of file names so that it can build a list of of those names along with their file sizes. Once all that information has been collected store it as the header in the result output file. After thant make a second pass through the arguments but this time actually load each of the files and copy them to the output file.

You will want to read the input files and write the output file in binary mode instead of text mode so that the output file can contain any mixture of text and binary files.

I know that perhaps a header file is needed(containing filename, size of filename, start and end of file) for extracting these files back out into their original form, but how would I go about doing this.

Here's a simple example where each file is preceded by a header with the name and size. Please excuse any errors or issues, it was written in haste:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define ARCHIVE "-a"
#define EXTRACT "-e"
#define MAX_NAME 512
#define BLOCK_SIZE 512

struct header {
    char name[MAX_NAME];
    size_t size;
};

static void add_to_archive(FILE *archive, FILE *src, const char *src_name)
{
    struct header hdr;
    char block[BLOCK_SIZE];
    size_t n;

    fseek(src, 0, SEEK_END);
    strcpy(hdr.name, src_name);
    hdr.size = ftell(src);
    fseek(src, 0, SEEK_SET);

    fwrite(&hdr, sizeof hdr, 1, archive);
    
    while ((n = fread(block, 1, sizeof block, src)) > 0)
        fwrite(block, 1, n, archive);
}

static void extract_all(FILE *archive)
{
    struct header hdr;

    while (fread(&hdr, sizeof hdr, 1, archive) > 0) {
        FILE *dst = fopen(hdr.name, "wb");

        if (dst) {
            char block[BLOCK_SIZE];
            size_t total = 0;

            while (total < hdr.size) {
                size_t left_over = hdr.size - total;
                size_t to_read = left_over >= BLOCK_SIZE ? BLOCK_SIZE : left_over;
                size_t n = fread(block, 1, to_read, archive);

                total += n;
                fwrite(block, 1, n, dst);
            }

            fclose(dst);
        }
    }
}

static char *generate_archive_name(void)
{
    static char archive_name[MAX_NAME];
    
    char salt[5];
    time_t now = time(NULL);
    struct tm *curr = localtime(&now);

    strftime(archive_name, sizeof archive_name, "%Y%m%d%H%M%S", curr);
    sprintf(salt, "%d", rand() % 10000);
    strcat(archive_name, salt);
    strcat(archive_name, ".ar");

    return archive_name;
}

int main(int argc, char *argv[])
{
    srand((unsigned)time(NULL));

    if (argc > 1) {
        if (strcmp(argv[1], ARCHIVE) == 0) {
            FILE *archive = fopen(generate_archive_name(), "ab");

            if (archive) {
                int i;

                for (i = 2; i < argc; i++) {
                    FILE *in = fopen(argv[i], "rb");

                    if (in) {
                        add_to_archive(archive, in, argv[i]);
                        fclose(in);
                    }
                }

                fclose(archive);
            }
        }
        else if (strcmp(argv[1], EXTRACT) == 0) {
            if (argc > 2) {
                FILE *archive = fopen(argv[2], "rb");

                if (archive) {
                    extract_all(archive);
                    fclose(archive);
                }
            }
        }
        else {
            fprintf(stderr, "Invalid switch '%s'\n", argv[1]);
            return EXIT_FAILURE;
        }
    }

    return EXIT_SUCCESS;
}

Thank you so much for your time and effort and contribution for helping me.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.