#include <fcntl.h>
#include <unistd.h>
#include <zck.h>
+#include <argp.h>
#include "buzhash/buzhash.h"
#include "memmem.h"
+static char doc[] = "zck - Create a new zchunk file";
+
+static char args_doc[] = "<file>";
+
+void version() {
+ printf(ZCK_NAME " " ZCK_VERSION "\nCopyright (c) 2018 Jonathan Dieter\n");
+ exit(0);
+}
+
+static struct argp_option options[] = {
+ {"verbose", 'v', 0, 0,
+ "Increase verbosity (can be specified more than once for debugging)"},
+ {"quiet", 'q', 0, 0, "Only show errors"},
+ {"split", 's', "STRING", 0, "Split chunks at beginning of STRING"},
+ {"dict", 'D', "FILE", 0, "Set zstd compression dictionary to FILE"},
+ {"version", 'V', 0, 0, "Show program version"},
+ { 0 }
+};
+
+struct arguments {
+ char *args[1];
+ zck_log_type log_level;
+ char *split_string;
+ char *dict;
+};
+
+static error_t parse_opt (int key, char *arg, struct argp_state *state) {
+ struct arguments *arguments = state->input;
+
+ switch (key) {
+ case 'v':
+ arguments->log_level -= 1;
+ if(arguments->log_level < ZCK_LOG_DEBUG)
+ arguments->log_level = ZCK_LOG_DEBUG;
+ break;
+ case 'q':
+ arguments->log_level = ZCK_LOG_ERROR;
+ break;
+ case 's':
+ arguments->split_string = arg;
+ break;
+ case 'D':
+ arguments->dict = arg;
+ break;
+ case 'V':
+ version();
+ break;
+
+ case ARGP_KEY_ARG:
+ if (state->arg_num >= 1) {
+ argp_usage (state);
+ return EINVAL;
+ }
+ arguments->args[state->arg_num] = arg;
+
+ break;
+
+ case ARGP_KEY_END:
+ if (state->arg_num < 1) {
+ argp_usage (state);
+ return EINVAL;
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp argp = {options, parse_opt, args_doc, doc};
+
int main (int argc, char *argv[]) {
+ struct arguments arguments = {0};
+
+ /* Defaults */
+ arguments.log_level = ZCK_LOG_WARNING;
+
+ argp_parse (&argp, argc, argv, 0, 0, &arguments);
+
+ zck_set_log_level(arguments.log_level);
+
char *out_name;
+ out_name = malloc(strlen(arguments.args[0]) + 5);
+ snprintf(out_name, strlen(arguments.args[0]) + 5, "%s.zck",
+ arguments.args[0]);
+
+ /* Set dictionary if available */
char *dict = NULL;
size_t dict_size = 0;
-
- zck_set_log_level(ZCK_LOG_DEBUG);
-
- if(argc < 3 || argc > 4) {
- printf("Usage: %s <file> <split string> [optional dictionary]\n", argv[0]);
- exit(1);
- }
- out_name = malloc(strlen(argv[1]) + 5);
- snprintf(out_name, strlen(argv[1]) + 5, "%s.zck", argv[1]);
- if(argc == 4) {
- int dict_fd = open(argv[3], O_RDONLY);
+ if(arguments.dict != NULL) {
+ int dict_fd = open(arguments.dict, O_RDONLY);
if(dict_fd < 0) {
- printf("Unable to open dictionary %s for reading", argv[3]);
+ printf("Unable to open dictionary %s for reading", arguments.dict);
perror("");
exit(1);
}
close(dict_fd);
}
- int dst_fd = open(out_name, O_EXCL | O_WRONLY | O_CREAT, 0644);
+ int dst_fd = open(out_name, O_TRUNC | O_WRONLY | O_CREAT, 0644);
if(dst_fd < 0) {
printf("Unable to open %s", out_name);
perror("");
free(dict);
char *data;
- int in_fd = open(argv[1], O_RDONLY);
- int in_size = 0;
+ int in_fd = open(arguments.args[0], O_RDONLY);
+ off_t in_size = 0;
if(in_fd < 0) {
printf("Unable to open %s for reading", argv[1]);
perror("");
}
close(in_fd);
- /* Chunk based on string in argv[2] (Currently with ugly hack to group srpms together) */
- if(False) {
+ if(arguments.split_string) {
char *found = data;
char *search = found;
char *prev_srpm = memmem(search, in_size - (search-data), "<rpm:sourcerpm", 14);
char *start = data;
char *window_loc;
+ if(arguments.log_level <= ZCK_LOG_INFO) {
+ printf("Using buzhash algorithm for automatic chunking\n");
+ printf("Window size: %lu\n", buzhash_width);
+ }
while(cur_loc < data + in_size) {
uint32_t bh = 0;
window_loc = cur_loc;
cur_loc += buzhash_width;
while(cur_loc < data + in_size) {
bh = buzhash_update(cur_loc, bh);
- if(((bh) & (8192 - 1)) == 0)
+ if(((bh) & (buzhash_width - 1)) == 0)
break;
cur_loc++;
}
} else {
cur_loc = data + in_size;
}
- printf("Completing %li bytes\n", (long)(cur_loc-start));
+ if(arguments.log_level <= ZCK_LOG_DEBUG)
+ printf("Completing %li bytes\n", (long)(cur_loc-start));
if(zck_write(zck, start, cur_loc-start) < 0)
exit(1);
if(zck_end_chunk(zck) < 0)
}
if(!zck_close(zck))
exit(1);
+ if(arguments.log_level <= ZCK_LOG_INFO) {
+ zckIndex *idx = zck_get_index(zck);
+ printf("Wrote %lu bytes in %lu chunks\n",
+ zck_get_data_length(zck) + zck_get_header_length(zck),
+ idx->count);
+ }
+
zck_free(&zck);
close(dst_fd);
}