Skip to content

Instantly share code, notes, and snippets.

@shawnfeng0
Created May 30, 2023 16:34
Show Gist options
  • Save shawnfeng0/05461a2cba5ad7d14c3da332cbfdd4f4 to your computer and use it in GitHub Desktop.
Save shawnfeng0/05461a2cba5ad7d14c3da332cbfdd4f4 to your computer and use it in GitHub Desktop.
#include <archive.h>
#include <archive_entry.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <string>
#include <vector>
static void msg(const char *m) { write(1, m, strlen(m)); }
static void errmsg(const char *m) {
if (m == NULL) {
m = "Error: No error description provided.\n";
}
write(2, m, strlen(m));
}
static int verbose = 1;
static char buff[16384];
enum class CompressAlgorithm { NONE, GZIP, ZSTD };
static void create(const std::string &output_filename, CompressAlgorithm algo,
const std::vector<std::string> &path_list) {
struct archive *a = archive_write_new();
switch (algo) {
case CompressAlgorithm::GZIP:
archive_write_add_filter_gzip(a);
break;
case CompressAlgorithm::ZSTD:
archive_write_add_filter_zstd(a);
break;
case CompressAlgorithm::NONE:
default:
archive_write_add_filter_none(a);
break;
}
archive_write_set_format_gnutar(a);
archive_write_open_filename(a, output_filename.c_str());
for (const auto &path : path_list) {
struct archive *disk = archive_read_disk_new();
int r = archive_read_disk_open(disk, path.c_str());
if (r != ARCHIVE_OK) {
errmsg(archive_error_string(disk));
errmsg("\n");
exit(1);
}
for (;;) {
struct archive_entry *entry = archive_entry_new();
r = archive_read_next_header2(disk, entry);
if (r == ARCHIVE_EOF) break;
if (r != ARCHIVE_OK) {
errmsg(archive_error_string(disk));
errmsg("\n");
exit(1);
}
archive_read_disk_descend(disk);
msg("a ");
msg(archive_entry_pathname(entry));
r = archive_write_header(a, entry);
if (r < ARCHIVE_OK) {
errmsg(": ");
errmsg(archive_error_string(a));
}
if (r == ARCHIVE_FATAL) exit(1);
if (r > ARCHIVE_FAILED) {
/* For now, we use a simpler loop to copy data
* into the target archive. */
const int fd = open(archive_entry_sourcepath(entry), O_RDONLY);
ssize_t len = read(fd, buff, sizeof(buff));
while (len > 0) {
archive_write_data(a, buff, len);
len = read(fd, buff, sizeof(buff));
}
close(fd);
}
archive_entry_free(entry);
msg("\n");
}
archive_read_close(disk);
archive_read_free(disk);
}
archive_write_close(a);
archive_write_free(a);
}
int main(int argc, char *const *argv) {
const char *filename = NULL;
int opt;
while ((opt = getopt(argc, argv, "f:")) != -1) {
switch (opt) {
case 'f':
filename = optarg;
break;
case '?':
fprintf(stderr, "Usage: %s -f filename\n", argv[0]);
exit(EXIT_FAILURE);
}
}
if (filename == NULL) {
fprintf(stderr, "Usage: %s -f filename\n", argv[0]);
exit(EXIT_FAILURE);
}
printf("Using file: %s\n", filename);
argv += optind;
std::vector<std::string> path_list;
for (int i = 0; argv[i] != nullptr; i++) {
path_list.push_back(argv[i]);
printf("Unused argument: %s\n", argv[i]);
}
create(filename, CompressAlgorithm::GZIP, path_list);
return (0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment