Implement extracting from archive
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 5s
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 5s
TODO: Storing file permissions to be extracted with same permissions. Archiving and extracting symbolic links.
This commit is contained in:
parent
0449ab389e
commit
da2a0f7b1c
5 changed files with 224 additions and 11 deletions
208
src/archiver.c
208
src/archiver.c
|
@ -526,7 +526,8 @@ int simple_archiver_write_all(FILE *out_f, SDArchiverState *state,
|
||||||
return SDAS_SUCCESS;
|
return SDAS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int simple_archiver_print_archive_info(FILE *in_f) {
|
int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
|
||||||
|
const SDArchiverState *state) {
|
||||||
unsigned char buf[1024];
|
unsigned char buf[1024];
|
||||||
memset(buf, 0, 1024);
|
memset(buf, 0, 1024);
|
||||||
uint16_t u16;
|
uint16_t u16;
|
||||||
|
@ -547,6 +548,8 @@ int simple_archiver_print_archive_info(FILE *in_f) {
|
||||||
return SDAS_INVALID_FILE;
|
return SDAS_INVALID_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((cleanup(free_malloced_memory))) void *decompressor_cmd = NULL;
|
||||||
|
|
||||||
if ((buf[0] & 1) != 0) {
|
if ((buf[0] & 1) != 0) {
|
||||||
fprintf(stderr, "De/compressor flag is set.\n");
|
fprintf(stderr, "De/compressor flag is set.\n");
|
||||||
is_compressed = 1;
|
is_compressed = 1;
|
||||||
|
@ -586,6 +589,9 @@ int simple_archiver_print_archive_info(FILE *in_f) {
|
||||||
}
|
}
|
||||||
buf[1023] = 0;
|
buf[1023] = 0;
|
||||||
fprintf(stderr, "Decompressor cmd: %s\n", buf);
|
fprintf(stderr, "Decompressor cmd: %s\n", buf);
|
||||||
|
decompressor_cmd = malloc(u16 + 1);
|
||||||
|
memcpy((char *)decompressor_cmd, buf, u16 + 1);
|
||||||
|
((char *)decompressor_cmd)[u16] = 0;
|
||||||
} else {
|
} else {
|
||||||
__attribute__((cleanup(free_malloced_memory))) void *heap_buf =
|
__attribute__((cleanup(free_malloced_memory))) void *heap_buf =
|
||||||
malloc(u16 + 1);
|
malloc(u16 + 1);
|
||||||
|
@ -607,6 +613,7 @@ int simple_archiver_print_archive_info(FILE *in_f) {
|
||||||
fprintf(stderr, "File count is %u\n", u32);
|
fprintf(stderr, "File count is %u\n", u32);
|
||||||
|
|
||||||
uint32_t size = u32;
|
uint32_t size = u32;
|
||||||
|
int skip = 0;
|
||||||
for (uint32_t idx = 0; idx < size; ++idx) {
|
for (uint32_t idx = 0; idx < size; ++idx) {
|
||||||
fprintf(stderr, "\nFile %10u of %10u.\n", idx + 1, size);
|
fprintf(stderr, "\nFile %10u of %10u.\n", idx + 1, size);
|
||||||
if (feof(in_f) || ferror(in_f)) {
|
if (feof(in_f) || ferror(in_f)) {
|
||||||
|
@ -615,12 +622,33 @@ int simple_archiver_print_archive_info(FILE *in_f) {
|
||||||
return SDAS_INVALID_FILE;
|
return SDAS_INVALID_FILE;
|
||||||
}
|
}
|
||||||
simple_archiver_helper_16_bit_be(&u16);
|
simple_archiver_helper_16_bit_be(&u16);
|
||||||
|
__attribute__((cleanup(free_FILE_helper))) FILE *out_f = NULL;
|
||||||
if (u16 < 1024) {
|
if (u16 < 1024) {
|
||||||
if (fread(buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
if (fread(buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
||||||
return SDAS_INVALID_FILE;
|
return SDAS_INVALID_FILE;
|
||||||
}
|
}
|
||||||
buf[1023] = 0;
|
buf[1023] = 0;
|
||||||
fprintf(stderr, " Filename: %s\n", buf);
|
fprintf(stderr, " Filename: %s\n", buf);
|
||||||
|
if (do_extract) {
|
||||||
|
if ((state->parsed->flags & 0x8) == 0) {
|
||||||
|
__attribute__((cleanup(free_FILE_helper))) FILE *test_fd =
|
||||||
|
fopen((const char *)buf, "rb");
|
||||||
|
if (test_fd) {
|
||||||
|
skip = 1;
|
||||||
|
fprintf(stderr,
|
||||||
|
" WARNING: File already exists and "
|
||||||
|
"\"--overwrite-extract\" is not specified, skipping!\n");
|
||||||
|
} else {
|
||||||
|
skip = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
skip = 0;
|
||||||
|
}
|
||||||
|
if (!skip) {
|
||||||
|
simple_archiver_helper_make_dirs((const char *)buf);
|
||||||
|
out_f = fopen((const char *)buf, "wb");
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
__attribute__((cleanup(free_malloced_memory))) void *heap_buf =
|
__attribute__((cleanup(free_malloced_memory))) void *heap_buf =
|
||||||
malloc(u16 + 1);
|
malloc(u16 + 1);
|
||||||
|
@ -630,6 +658,26 @@ int simple_archiver_print_archive_info(FILE *in_f) {
|
||||||
}
|
}
|
||||||
uc_heap_buf[u16 - 1] = 0;
|
uc_heap_buf[u16 - 1] = 0;
|
||||||
fprintf(stderr, " Filename: %s\n", uc_heap_buf);
|
fprintf(stderr, " Filename: %s\n", uc_heap_buf);
|
||||||
|
if (do_extract) {
|
||||||
|
if ((state->parsed->flags & 0x8) == 0) {
|
||||||
|
__attribute__((cleanup(free_FILE_helper))) FILE *test_fd =
|
||||||
|
fopen((const char *)buf, "rb");
|
||||||
|
if (test_fd) {
|
||||||
|
skip = 1;
|
||||||
|
fprintf(stderr,
|
||||||
|
"WARNING: File already exists and \"--overwrite-extract\" "
|
||||||
|
"is not specified, skipping!\n");
|
||||||
|
} else {
|
||||||
|
skip = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
skip = 0;
|
||||||
|
}
|
||||||
|
if (!skip) {
|
||||||
|
simple_archiver_helper_make_dirs((const char *)uc_heap_buf);
|
||||||
|
out_f = fopen((const char *)buf, "wb");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fread(buf, 1, 4, in_f) != 4) {
|
if (fread(buf, 1, 4, in_f) != 4) {
|
||||||
|
@ -647,17 +695,159 @@ int simple_archiver_print_archive_info(FILE *in_f) {
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, " File size: %lu\n", u64);
|
fprintf(stderr, " File size: %lu\n", u64);
|
||||||
}
|
}
|
||||||
while (u64 > 0) {
|
|
||||||
if (u64 > 1024) {
|
if (do_extract && !skip) {
|
||||||
if (fread(buf, 1, 1024, in_f) != 1024) {
|
fprintf(stderr, " Extracting...\n");
|
||||||
return SDAS_INVALID_FILE;
|
int pipe_into_cmd[2];
|
||||||
|
int pipe_outof_cmd[2];
|
||||||
|
pid_t decompressor_pid;
|
||||||
|
if (pipe(pipe_into_cmd) != 0) {
|
||||||
|
// Unable to create pipes.
|
||||||
|
break;
|
||||||
|
} else if (pipe(pipe_outof_cmd) != 0) {
|
||||||
|
// Unable to create second set of pipes.
|
||||||
|
close(pipe_into_cmd[0]);
|
||||||
|
close(pipe_into_cmd[1]);
|
||||||
|
return 1;
|
||||||
|
} else if (fcntl(pipe_into_cmd[1], F_SETFL, O_NONBLOCK) != 0) {
|
||||||
|
// Unable to set non-blocking on into-write-pipe.
|
||||||
|
close(pipe_into_cmd[0]);
|
||||||
|
close(pipe_into_cmd[1]);
|
||||||
|
close(pipe_outof_cmd[0]);
|
||||||
|
close(pipe_outof_cmd[1]);
|
||||||
|
return 1;
|
||||||
|
} else if (fcntl(pipe_outof_cmd[0], F_SETFL, O_NONBLOCK) != 0) {
|
||||||
|
// Unable to set non-blocking on outof-read-pipe.
|
||||||
|
close(pipe_into_cmd[0]);
|
||||||
|
close(pipe_into_cmd[1]);
|
||||||
|
close(pipe_outof_cmd[0]);
|
||||||
|
close(pipe_outof_cmd[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state && state->parsed && state->parsed->decompressor) {
|
||||||
|
if (simple_archiver_de_compress(pipe_into_cmd, pipe_outof_cmd,
|
||||||
|
state->parsed->decompressor,
|
||||||
|
&decompressor_pid) != 0) {
|
||||||
|
// Failed to spawn compressor.
|
||||||
|
close(pipe_into_cmd[1]);
|
||||||
|
close(pipe_outof_cmd[0]);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
u64 -= 1024;
|
|
||||||
} else {
|
} else {
|
||||||
if (fread(buf, 1, u64, in_f) != u64) {
|
if (simple_archiver_de_compress(pipe_into_cmd, pipe_outof_cmd,
|
||||||
return SDAS_INVALID_FILE;
|
decompressor_cmd,
|
||||||
|
&decompressor_pid) != 0) {
|
||||||
|
// Failed to spawn compressor.
|
||||||
|
close(pipe_into_cmd[1]);
|
||||||
|
close(pipe_outof_cmd[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close unnecessary pipe fds on this end of the transfer.
|
||||||
|
close(pipe_into_cmd[0]);
|
||||||
|
close(pipe_outof_cmd[1]);
|
||||||
|
|
||||||
|
uint64_t compressed_file_size = u64;
|
||||||
|
int write_again = 0;
|
||||||
|
int write_pipe_done = 0;
|
||||||
|
int read_pipe_done = 0;
|
||||||
|
ssize_t fread_ret;
|
||||||
|
char recv_buf[1024];
|
||||||
|
size_t amount_to_read;
|
||||||
|
while (!write_pipe_done || !read_pipe_done) {
|
||||||
|
// Read from file.
|
||||||
|
if (!write_pipe_done) {
|
||||||
|
if (!write_again && compressed_file_size != 0) {
|
||||||
|
if (compressed_file_size > 1024) {
|
||||||
|
amount_to_read = 1024;
|
||||||
|
} else {
|
||||||
|
amount_to_read = compressed_file_size;
|
||||||
|
}
|
||||||
|
fread_ret = fread(buf, 1, amount_to_read, in_f);
|
||||||
|
if (fread_ret > 0) {
|
||||||
|
compressed_file_size -= fread_ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send over pipe to decompressor.
|
||||||
|
if (fread_ret > 0) {
|
||||||
|
ssize_t write_ret = write(pipe_into_cmd[1], buf, fread_ret);
|
||||||
|
if (write_ret == fread_ret) {
|
||||||
|
// Successful write.
|
||||||
|
write_again = 0;
|
||||||
|
if (compressed_file_size == 0) {
|
||||||
|
close(pipe_into_cmd[1]);
|
||||||
|
write_pipe_done = 1;
|
||||||
|
}
|
||||||
|
} else if (write_ret == -1) {
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
|
write_again = 1;
|
||||||
|
} else {
|
||||||
|
// Error.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Should be unreachable, error.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read output from decompressor and write to file.
|
||||||
|
if (!read_pipe_done) {
|
||||||
|
ssize_t read_ret = read(pipe_outof_cmd[0], recv_buf, 1024);
|
||||||
|
if (read_ret > 0) {
|
||||||
|
size_t fwrite_ret = fwrite(recv_buf, 1, read_ret, out_f);
|
||||||
|
if (fwrite_ret == (size_t)read_ret) {
|
||||||
|
// Success.
|
||||||
|
} else if (ferror(out_f)) {
|
||||||
|
// Error.
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
// Invalid state, error.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (read_ret == -1) {
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
|
// No bytes to read yet.
|
||||||
|
} else {
|
||||||
|
// Error.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (read_ret == 0) {
|
||||||
|
// EOF.
|
||||||
|
read_pipe_done = 1;
|
||||||
|
close(pipe_outof_cmd[0]);
|
||||||
|
free_FILE_helper(&out_f);
|
||||||
|
} else {
|
||||||
|
// Invalid state (unreachable?), error.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waitpid(decompressor_pid, NULL, 0);
|
||||||
|
|
||||||
|
fprintf(stderr, " Extracted.\n");
|
||||||
|
} else {
|
||||||
|
while (u64 != 0) {
|
||||||
|
if (u64 > 1024) {
|
||||||
|
ssize_t read_ret = fread(buf, 1, 1024, in_f);
|
||||||
|
if (read_ret > 0) {
|
||||||
|
u64 -= read_ret;
|
||||||
|
} else if (ferror(in_f)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ssize_t read_ret = fread(buf, 1, u64, in_f);
|
||||||
|
if (read_ret > 0) {
|
||||||
|
u64 -= read_ret;
|
||||||
|
} else if (ferror(in_f)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
u64 = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -53,7 +53,8 @@ int simple_archiver_write_all(FILE *out_f, SDArchiverState *state,
|
||||||
const SDArchiverLinkedList *filenames);
|
const SDArchiverLinkedList *filenames);
|
||||||
|
|
||||||
/// Returns zero on success.
|
/// Returns zero on success.
|
||||||
int simple_archiver_print_archive_info(FILE *in_f);
|
int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
|
||||||
|
const SDArchiverState *state);
|
||||||
|
|
||||||
/// Returns zero on success.
|
/// Returns zero on success.
|
||||||
int simple_archiver_de_compress(int pipe_fd_in[2], int pipe_fd_out[2],
|
int simple_archiver_de_compress(int pipe_fd_in[2], int pipe_fd_out[2],
|
||||||
|
|
17
src/main.c
17
src/main.c
|
@ -83,10 +83,25 @@ int main(int argc, const char **argv) {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (simple_archiver_print_archive_info(file) != 0) {
|
if (simple_archiver_parse_archive_info(file, 0, NULL) != 0) {
|
||||||
fprintf(stderr, "Error during archive checking/examining.\n");
|
fprintf(stderr, "Error during archive checking/examining.\n");
|
||||||
}
|
}
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
} else if ((parsed.flags & 3) == 1) {
|
||||||
|
FILE *file = fopen(parsed.filename, "rb");
|
||||||
|
if (!file) {
|
||||||
|
fprintf(stderr, "ERROR: Failed to open \"%s\" for reading!\n",
|
||||||
|
parsed.filename);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((cleanup(simple_archiver_free_state)))
|
||||||
|
SDArchiverState *state = simple_archiver_init_state(&parsed);
|
||||||
|
|
||||||
|
if (simple_archiver_parse_archive_info(file, 1, state) != 0) {
|
||||||
|
fprintf(stderr, "Error during archive extracting.\n");
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -143,7 +143,11 @@ void simple_archiver_print_usage(void) {
|
||||||
"--compressor <full_compress_cmd> : requires --decompressor\n");
|
"--compressor <full_compress_cmd> : requires --decompressor\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"--decompressor <full_decompress_cmd> : requires --compressor\n");
|
"--decompressor <full_decompress_cmd> : requires --compressor\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" Specifying \"--decompressor\" when extracting overrides archive "
|
||||||
|
"file's stored decompressor\n");
|
||||||
fprintf(stderr, "--overwrite-create : allows overwriting an archive file\n");
|
fprintf(stderr, "--overwrite-create : allows overwriting an archive file\n");
|
||||||
|
fprintf(stderr, "--overwrite-extract : allows overwriting when extracting\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"-- : specifies remaining arguments are files to archive/extract\n");
|
"-- : specifies remaining arguments are files to archive/extract\n");
|
||||||
fprintf(
|
fprintf(
|
||||||
|
@ -225,6 +229,8 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
++argv;
|
++argv;
|
||||||
} else if (strcmp(argv[0], "--overwrite-create") == 0) {
|
} else if (strcmp(argv[0], "--overwrite-create") == 0) {
|
||||||
out->flags |= 0x4;
|
out->flags |= 0x4;
|
||||||
|
} else if (strcmp(argv[0], "--overwrite-extract") == 0) {
|
||||||
|
out->flags |= 0x8;
|
||||||
} else if (argv[0][0] == '-' && argv[0][1] == '-' && argv[0][2] == 0) {
|
} else if (argv[0][0] == '-' && argv[0][1] == '-' && argv[0][2] == 0) {
|
||||||
is_remaining_args = 1;
|
is_remaining_args = 1;
|
||||||
} else if (argv[0][0] != '-') {
|
} else if (argv[0][0] != '-') {
|
||||||
|
|
|
@ -28,6 +28,7 @@ typedef struct SDArchiverParsed {
|
||||||
/// 0b xxxx xx10 - is checking/examining.
|
/// 0b xxxx xx10 - is checking/examining.
|
||||||
/// 0b xxxx x0xx - Do NOT allow create archive overwrite.
|
/// 0b xxxx x0xx - Do NOT allow create archive overwrite.
|
||||||
/// 0b xxxx x1xx - Allow create archive overwrite.
|
/// 0b xxxx x1xx - Allow create archive overwrite.
|
||||||
|
/// 0b xxxx 1xxx - Allow extract overwrite.
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
/// Null-terminated string.
|
/// Null-terminated string.
|
||||||
char *filename;
|
char *filename;
|
||||||
|
|
Loading…
Reference in a new issue