diff --git a/src/main.c b/src/main.c index ef1af7a..a9d4ba6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,4 +1,5 @@ #define _DEFAULT_SOURCE +#include #include #include #include @@ -12,7 +13,7 @@ #include #define MAGIC_SIZE 5 -#define CAV_PASSES 3 +#define CAV_PASSES 2 #define CAV_VERSION "0.0.1" #define CAV_OFF_INDEX(INDEX) \ @@ -57,7 +58,7 @@ struct cav_offset { char magic[MAGIC_SIZE]; uint32_t off; size_t size; -}; +} __attribute__((packed)); /* * Represents an offset descriptor used before holding @@ -163,7 +164,7 @@ state_init(struct cav_state *state) return -1; } - state->out_fd = open(output_name, O_WRONLY | O_CREAT, 0600); + state->out_fd = open(output_name, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (state->out_fd < 0) { close(state->dir_fd); return -1; @@ -264,6 +265,79 @@ consume_scan(const char *dir_path, struct cav_state *state, DIR *subdir) } } +/* + * File a file segment within the archive + * + * @state: Cav state + * @desc: Offset descriptor + */ +static void +fill_segment(struct cav_state *state, struct cav_offdesc *desc) +{ + struct cav_offset *off; + void *mem; + int fd; + + if (state == NULL || desc == NULL) { + return; + } + + off = &desc->off; + fd = open(desc->path, O_RDONLY); + if (fd < 0) { + perror("open"); + return; + } + + /* Map the file */ + mem = mmap( + NULL, + off->size, + PROT_READ, + MAP_SHARED, + fd, + 0 + ); + + /* File name goes before file contents */ + write(state->out_fd, desc->path, strlen(desc->path) + 1); + write(state->out_fd, mem, off->size); + + /* Clean up */ + munmap(mem, off->size); + close(fd); +} + +/* + * Construct the on-disk offset table + * + * @state: Cav state + */ +static void +build_offtab(struct cav_state *state) +{ + struct cav_offdesc *off_desc; + struct cav_offset *off; + + if (state == NULL) { + return; + } + + /* First, write out the offset table */ + TAILQ_FOREACH(off_desc, &state->offq, link) { + off = &off_desc->off; + off->off = state->cur_off; + + state->cur_off += off->size; + write(state->out_fd, off, sizeof(*off)); + } + + /* Next, write out the segments */ + TAILQ_FOREACH(off_desc, &state->offq, link) { + fill_segment(state, off_desc); + } +} + /* * Consume a single pass in our yummy yummy consumption * process only to be thrown up again along with stomach @@ -272,8 +346,6 @@ consume_scan(const char *dir_path, struct cav_state *state, DIR *subdir) static void consume_pass(struct cav_state *state) { - struct cav_offdesc *off; - if (state == NULL) { return; } @@ -287,11 +359,11 @@ consume_pass(struct cav_state *state) state->file_count, state->cur_off ); - - TAILQ_FOREACH(off, &state->offq, link) { - printf("[*] %s\n", off->path); - } - + break; + case 1: + printf("[pass 1] building offset table + segments...\n"); + state->cur_off = CAV_OFF_INDEX(state->file_count); + build_offtab(state); break; } } @@ -333,9 +405,9 @@ main(int argc, char **argv) /* * There are three passes required in the consumption operation * - * pass 0): Obtain number of files for offset table creation - * pass 1): Construct an offset table using what we know - * pass 2): Construct the archive segments + * pass 0): Obtain number of files for offset table creation. + * pass 1): Construct an offset table using what we know and + * populate file entries. */ for (int i = 0; i < CAV_PASSES; ++i) { consume_pass(&state);