2024-08-30 02:35:17 +00:00
|
|
|
// ISC License
|
2024-09-01 06:11:57 +00:00
|
|
|
//
|
2024-08-30 02:35:17 +00:00
|
|
|
// Copyright (c) 2024 Stephen Seo
|
2024-09-01 06:11:57 +00:00
|
|
|
//
|
2024-08-30 02:35:17 +00:00
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
|
|
// copyright notice and this permission notice appear in all copies.
|
2024-09-01 06:11:57 +00:00
|
|
|
//
|
2024-08-30 02:35:17 +00:00
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
|
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
|
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
// PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
//
|
|
|
|
// `archiver.c` is the source for an interface to creating an archive file.
|
2024-07-16 07:16:58 +00:00
|
|
|
|
|
|
|
#include "archiver.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2024-07-17 06:01:39 +00:00
|
|
|
#include "platforms.h"
|
2024-07-17 05:32:39 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
2024-07-17 07:37:32 +00:00
|
|
|
#include <errno.h>
|
2024-07-17 05:32:39 +00:00
|
|
|
#include <fcntl.h>
|
2024-07-23 06:28:59 +00:00
|
|
|
#include <libgen.h>
|
|
|
|
#include <limits.h>
|
2024-07-19 03:13:54 +00:00
|
|
|
#include <signal.h>
|
2024-07-17 05:32:39 +00:00
|
|
|
#include <spawn.h>
|
2024-07-18 05:02:15 +00:00
|
|
|
#include <sys/stat.h>
|
2024-07-17 10:00:34 +00:00
|
|
|
#include <sys/wait.h>
|
2024-07-17 05:32:39 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2024-07-16 07:16:58 +00:00
|
|
|
#include "helpers.h"
|
|
|
|
|
2024-09-06 05:23:27 +00:00
|
|
|
#define TEMP_FILENAME_CMP "%s%ssimple_archiver_compressed_%lu.tmp"
|
|
|
|
#define FILE_COUNTS_OUTPUT_FORMAT_STR_0 "\nFile %%%lulu of %%%lulu.\n"
|
|
|
|
#define FILE_COUNTS_OUTPUT_FORMAT_STR_1 "[%%%lulu/%%%lulu]\n"
|
2024-07-17 07:37:32 +00:00
|
|
|
|
2024-07-19 03:15:20 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
2024-07-19 03:13:54 +00:00
|
|
|
int is_sig_pipe_occurred = 0;
|
|
|
|
|
|
|
|
void handle_sig_pipe(int sig) {
|
|
|
|
if (sig == SIGPIPE) {
|
|
|
|
is_sig_pipe_occurred = 1;
|
|
|
|
}
|
|
|
|
}
|
2024-07-19 03:15:20 +00:00
|
|
|
#endif
|
2024-07-19 03:13:54 +00:00
|
|
|
|
2024-07-16 07:16:58 +00:00
|
|
|
typedef struct SDArchiverInternalToWrite {
|
|
|
|
void *buf;
|
|
|
|
uint64_t size;
|
|
|
|
} SDArchiverInternalToWrite;
|
|
|
|
|
|
|
|
void free_internal_to_write(void *data) {
|
|
|
|
SDArchiverInternalToWrite *to_write = data;
|
|
|
|
free(to_write->buf);
|
|
|
|
free(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
int write_list_datas_fn(void *data, void *ud) {
|
|
|
|
SDArchiverInternalToWrite *to_write = data;
|
|
|
|
FILE *out_f = ud;
|
|
|
|
|
|
|
|
fwrite(to_write->buf, 1, to_write->size, out_f);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-07-18 13:56:12 +00:00
|
|
|
void cleanup_temp_filename_delete(void ***ptrs_array) {
|
2024-07-18 13:08:48 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
2024-07-18 13:56:12 +00:00
|
|
|
if (ptrs_array && *ptrs_array) {
|
|
|
|
if ((*ptrs_array)[1]) {
|
2024-07-29 07:31:10 +00:00
|
|
|
simple_archiver_helper_cleanup_FILE((FILE **)(*ptrs_array)[1]);
|
2024-07-18 13:56:12 +00:00
|
|
|
}
|
|
|
|
if ((*ptrs_array)[0]) {
|
|
|
|
unlink((char *)((*ptrs_array)[0]));
|
|
|
|
}
|
|
|
|
free(*ptrs_array);
|
|
|
|
*ptrs_array = NULL;
|
2024-07-18 13:08:48 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-07-24 05:04:19 +00:00
|
|
|
char *filename_to_absolute_path(const char *filename) {
|
2024-07-24 06:03:34 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(simple_archiver_helper_cleanup_malloced))) void *path =
|
2024-07-24 05:04:19 +00:00
|
|
|
malloc(strlen(filename) + 1);
|
|
|
|
strncpy(path, filename, strlen(filename) + 1);
|
|
|
|
|
|
|
|
char *path_dir = dirname(path);
|
|
|
|
if (!path_dir) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((
|
|
|
|
cleanup(simple_archiver_helper_cleanup_malloced))) void *dir_realpath =
|
2024-07-24 05:04:19 +00:00
|
|
|
realpath(path_dir, NULL);
|
|
|
|
if (!dir_realpath) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recreate "path" since it may have been modified by dirname().
|
2024-07-29 07:31:10 +00:00
|
|
|
simple_archiver_helper_cleanup_malloced(&path);
|
2024-07-24 05:04:19 +00:00
|
|
|
path = malloc(strlen(filename) + 1);
|
|
|
|
strncpy(path, filename, strlen(filename) + 1);
|
|
|
|
|
|
|
|
char *filename_basename = basename(path);
|
|
|
|
if (!filename_basename) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get combined full path to file.
|
|
|
|
char *fullpath =
|
|
|
|
malloc(strlen(dir_realpath) + 1 + strlen(filename_basename) + 1);
|
|
|
|
strncpy(fullpath, dir_realpath, strlen(dir_realpath) + 1);
|
|
|
|
fullpath[strlen(dir_realpath)] = '/';
|
|
|
|
strncpy(fullpath + strlen(dir_realpath) + 1, filename_basename,
|
|
|
|
strlen(filename_basename) + 1);
|
|
|
|
|
|
|
|
return fullpath;
|
2024-07-24 06:03:34 +00:00
|
|
|
#endif
|
|
|
|
return NULL;
|
2024-07-24 05:04:19 +00:00
|
|
|
}
|
|
|
|
|
2024-07-16 07:16:58 +00:00
|
|
|
int write_files_fn(void *data, void *ud) {
|
|
|
|
const SDArchiverFileInfo *file_info = data;
|
2024-07-16 07:44:54 +00:00
|
|
|
SDArchiverState *state = ud;
|
2024-07-16 07:16:58 +00:00
|
|
|
|
|
|
|
__attribute__((cleanup(simple_archiver_list_free)))
|
|
|
|
SDArchiverLinkedList *to_write = simple_archiver_list_init();
|
|
|
|
SDArchiverInternalToWrite *temp_to_write;
|
|
|
|
|
|
|
|
if (!file_info->filename) {
|
|
|
|
// Invalid entry, no filename.
|
|
|
|
return 1;
|
|
|
|
} else if (!state->out_f) {
|
|
|
|
// Invalid out-ptr.
|
|
|
|
return 1;
|
|
|
|
} else if (!file_info->link_dest) {
|
|
|
|
// Regular file, not a symbolic link.
|
|
|
|
if (state->parsed->compressor && state->parsed->decompressor) {
|
|
|
|
// De/compressor specified.
|
2024-07-17 07:37:32 +00:00
|
|
|
|
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
|
|
|
// Use temp file to store compressed data.
|
2024-07-25 01:42:31 +00:00
|
|
|
char temp_filename[512];
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t idx = 0;
|
|
|
|
size_t temp_dir_end = strlen(state->parsed->temp_dir);
|
2024-07-25 01:42:31 +00:00
|
|
|
snprintf(temp_filename, 512, TEMP_FILENAME_CMP, state->parsed->temp_dir,
|
|
|
|
state->parsed->temp_dir[temp_dir_end - 1] == '/' ? "" : "/",
|
|
|
|
idx);
|
2024-07-17 07:37:32 +00:00
|
|
|
do {
|
|
|
|
FILE *test_fd = fopen(temp_filename, "rb");
|
|
|
|
if (test_fd) {
|
|
|
|
// File exists.
|
|
|
|
fclose(test_fd);
|
2024-07-25 01:42:31 +00:00
|
|
|
snprintf(temp_filename, 512, TEMP_FILENAME_CMP,
|
|
|
|
state->parsed->temp_dir,
|
|
|
|
state->parsed->temp_dir[temp_dir_end - 1] == '/' ? "" : "/",
|
|
|
|
++idx);
|
2024-07-17 07:37:32 +00:00
|
|
|
} else if (idx > 0xFFFF) {
|
|
|
|
// Sanity check.
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (1);
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(simple_archiver_helper_cleanup_FILE)))
|
|
|
|
FILE *file_fd = fopen(file_info->filename, "rb");
|
2024-07-17 07:37:32 +00:00
|
|
|
if (!file_fd) {
|
|
|
|
// Unable to open file for compressing and archiving.
|
|
|
|
return 1;
|
|
|
|
}
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(simple_archiver_helper_cleanup_FILE)))
|
|
|
|
FILE *tmp_fd = fopen(temp_filename, "wb");
|
2024-07-25 01:42:31 +00:00
|
|
|
if (!tmp_fd) {
|
|
|
|
fprintf(stderr, "ERROR: Unable to create temp file for compressing!\n");
|
2024-07-26 07:23:50 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((
|
|
|
|
cleanup(simple_archiver_helper_cleanup_malloced))) void *real_cwd =
|
2024-07-26 07:23:50 +00:00
|
|
|
realpath(".", NULL);
|
2024-07-26 07:25:02 +00:00
|
|
|
if (real_cwd) {
|
|
|
|
fprintf(stderr, "Tried to create temp file(s) in \"%s\"!\n",
|
|
|
|
(char *)real_cwd);
|
|
|
|
}
|
2024-07-26 07:23:50 +00:00
|
|
|
#endif
|
2024-07-26 07:01:39 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"(Use \"--temp-files-dir <dir>\" to change where to write temp "
|
|
|
|
"files.)\n");
|
2024-07-25 01:42:31 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2024-07-18 13:56:12 +00:00
|
|
|
__attribute__((cleanup(cleanup_temp_filename_delete))) void **ptrs_array =
|
|
|
|
malloc(sizeof(void *) * 2);
|
|
|
|
ptrs_array[0] = temp_filename;
|
|
|
|
ptrs_array[1] = &tmp_fd;
|
2024-07-17 07:37:32 +00:00
|
|
|
|
2024-07-19 03:13:54 +00:00
|
|
|
// Handle SIGPIPE.
|
|
|
|
signal(SIGPIPE, handle_sig_pipe);
|
|
|
|
|
2024-07-17 07:37:32 +00:00
|
|
|
int pipe_into_cmd[2];
|
|
|
|
int pipe_outof_cmd[2];
|
2024-07-17 10:00:34 +00:00
|
|
|
pid_t compressor_pid;
|
2024-07-17 07:37:32 +00:00
|
|
|
|
|
|
|
if (pipe(pipe_into_cmd) != 0) {
|
|
|
|
// Unable to create pipes.
|
|
|
|
return 1;
|
|
|
|
} 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;
|
|
|
|
} else if (simple_archiver_de_compress(pipe_into_cmd, pipe_outof_cmd,
|
2024-07-17 10:00:34 +00:00
|
|
|
state->parsed->compressor,
|
|
|
|
&compressor_pid) != 0) {
|
2024-07-17 07:37:32 +00:00
|
|
|
// Failed to spawn compressor.
|
|
|
|
close(pipe_into_cmd[1]);
|
|
|
|
close(pipe_outof_cmd[0]);
|
2024-07-19 02:29:14 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to start compressor cmd! Invalid cmd?\n");
|
2024-07-17 07:37:32 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close unnecessary pipe fds on this end of the transfer.
|
|
|
|
close(pipe_into_cmd[0]);
|
|
|
|
close(pipe_outof_cmd[1]);
|
|
|
|
|
2024-07-18 13:32:04 +00:00
|
|
|
int compressor_status;
|
|
|
|
int compressor_return_val;
|
|
|
|
int compressor_ret = waitpid(compressor_pid, &compressor_status, WNOHANG);
|
|
|
|
if (compressor_ret == compressor_pid) {
|
|
|
|
// Status is available.
|
|
|
|
if (WIFEXITED(compressor_status)) {
|
|
|
|
compressor_return_val = WEXITSTATUS(compressor_status);
|
2024-07-19 02:29:14 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Exec failed (exec exit code %d)! Invalid "
|
|
|
|
"compressor cmd?\n",
|
|
|
|
compressor_return_val);
|
|
|
|
return 1;
|
2024-07-18 13:32:04 +00:00
|
|
|
}
|
|
|
|
} else if (compressor_ret == 0) {
|
|
|
|
// Probably still running, continue on.
|
|
|
|
} else {
|
|
|
|
// Error.
|
2024-07-19 02:29:14 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Exec failed (exec exit code unknown)! Invalid "
|
|
|
|
"compressor cmd?\n");
|
2024-07-18 13:32:04 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-07-17 07:37:32 +00:00
|
|
|
// Write file to pipe, and read from other pipe.
|
|
|
|
char write_buf[1024];
|
|
|
|
char read_buf[1024];
|
|
|
|
int write_again = 0;
|
|
|
|
int write_done = 0;
|
|
|
|
int read_done = 0;
|
|
|
|
size_t write_count;
|
|
|
|
size_t read_count;
|
|
|
|
ssize_t ret;
|
|
|
|
while (!write_done || !read_done) {
|
2024-07-19 03:13:54 +00:00
|
|
|
if (is_sig_pipe_occurred) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to write to compressor (SIGPIPE)! Invalid "
|
|
|
|
"compressor cmd?\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-07-17 07:37:32 +00:00
|
|
|
// Read from file.
|
|
|
|
if (!write_done) {
|
|
|
|
if (!write_again) {
|
|
|
|
write_count = fread(write_buf, 1, 1024, file_fd);
|
|
|
|
}
|
|
|
|
if (write_count > 0) {
|
|
|
|
ret = write(pipe_into_cmd[1], write_buf, write_count);
|
|
|
|
if (ret == -1) {
|
|
|
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
|
|
write_again = 1;
|
|
|
|
} else {
|
|
|
|
// Error during write.
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to write to compressor! Invalid "
|
|
|
|
"compressor cmd?\n");
|
2024-07-17 07:37:32 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else if ((size_t)ret != write_count) {
|
|
|
|
// Error during write.
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to write to compressor! Invalid "
|
|
|
|
"compressor cmd?\n");
|
2024-07-17 07:37:32 +00:00
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
write_again = 0;
|
|
|
|
// fprintf(stderr, "Written %zd bytes to comp.\n", ret);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (feof(file_fd)) {
|
2024-07-29 07:31:10 +00:00
|
|
|
simple_archiver_helper_cleanup_FILE(&file_fd);
|
2024-07-17 07:37:32 +00:00
|
|
|
write_done = 1;
|
|
|
|
close(pipe_into_cmd[1]);
|
|
|
|
// fprintf(stderr, "write_done\n");
|
|
|
|
} else if (ferror(file_fd)) {
|
|
|
|
// Error during read file.
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(
|
|
|
|
stderr,
|
|
|
|
"WARNING: Failed to write to compressor (failed to read)!\n");
|
2024-07-17 07:37:32 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read from compressor.
|
|
|
|
if (!read_done) {
|
|
|
|
ret = read(pipe_outof_cmd[0], read_buf, 1024);
|
|
|
|
if (ret > 0) {
|
2024-09-06 05:23:27 +00:00
|
|
|
read_count = fwrite(read_buf, 1, (size_t)ret, tmp_fd);
|
2024-07-17 07:37:32 +00:00
|
|
|
if (read_count != (size_t)ret) {
|
|
|
|
// Write to tmp_fd error.
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to read from compressor! Invalid "
|
|
|
|
"compressor cmd?\n");
|
2024-07-17 07:37:32 +00:00
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
// fprintf(stderr, "Written %zd bytes to tmp_fd.\n", read_count);
|
|
|
|
}
|
|
|
|
} else if (ret == 0) {
|
|
|
|
read_done = 1;
|
2024-07-29 07:31:10 +00:00
|
|
|
simple_archiver_helper_cleanup_FILE(&tmp_fd);
|
2024-07-17 07:37:32 +00:00
|
|
|
close(pipe_outof_cmd[0]);
|
|
|
|
// fprintf(stderr, "read_done\n");
|
|
|
|
} else if (ret == -1) {
|
|
|
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
|
|
// Nop.
|
|
|
|
} else {
|
|
|
|
// Read error.
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to read from compressor! Invalid "
|
|
|
|
"compressor cmd?\n");
|
2024-07-17 07:37:32 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Nop. Technically this branch should be unreachable.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-19 03:13:54 +00:00
|
|
|
if (is_sig_pipe_occurred) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to write to compressor (SIGPIPE)! Invalid "
|
|
|
|
"compressor cmd?\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-07-17 10:00:34 +00:00
|
|
|
waitpid(compressor_pid, NULL, 0);
|
|
|
|
|
2024-07-17 07:37:32 +00:00
|
|
|
uint16_t u16;
|
|
|
|
uint64_t u64;
|
|
|
|
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t temp_size = strlen(file_info->filename);
|
|
|
|
if (temp_size > 0xFFFF) {
|
|
|
|
fprintf(stderr, "ERROR: Filename size is too large to store!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
u16 = (uint16_t)temp_size;
|
2024-07-17 07:37:32 +00:00
|
|
|
|
|
|
|
// Write filename length.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(2);
|
|
|
|
temp_to_write->size = 2;
|
|
|
|
memcpy(temp_to_write->buf, &u16, 2);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Write filename.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(u16 + 1);
|
|
|
|
temp_to_write->size = u16 + 1;
|
|
|
|
memcpy(temp_to_write->buf, file_info->filename, u16 + 1);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Write flags.
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(4);
|
|
|
|
temp_to_write->size = 4;
|
2024-09-06 05:23:27 +00:00
|
|
|
for (size_t idx = 0; idx < temp_to_write->size; ++idx) {
|
2024-07-17 07:37:32 +00:00
|
|
|
((unsigned char *)temp_to_write->buf)[idx] = 0;
|
|
|
|
}
|
2024-07-18 05:02:15 +00:00
|
|
|
|
|
|
|
// Get file stats.
|
|
|
|
struct stat stat_buf;
|
|
|
|
memset(&stat_buf, 0, sizeof(struct stat));
|
|
|
|
int stat_fd = open(file_info->filename, O_RDONLY);
|
|
|
|
if (stat_fd == -1) {
|
|
|
|
// Error.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
int stat_status = fstat(stat_fd, &stat_buf);
|
|
|
|
close(stat_fd);
|
|
|
|
if (stat_status != 0) {
|
|
|
|
// Error.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((stat_buf.st_mode & S_IRUSR) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x2;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IWUSR) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x4;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IXUSR) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x8;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IRGRP) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x10;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IWGRP) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x20;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IXGRP) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x40;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IROTH) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x80;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IWOTH) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[1] |= 0x1;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IXOTH) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[1] |= 0x2;
|
|
|
|
}
|
|
|
|
|
2024-07-17 07:37:32 +00:00
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Get compressed file length.
|
|
|
|
// Compressed file should be at "temp_filename".
|
|
|
|
tmp_fd = fopen(temp_filename, "rb");
|
2024-07-18 13:56:12 +00:00
|
|
|
|
2024-07-17 07:37:32 +00:00
|
|
|
long end;
|
|
|
|
if (fseek(tmp_fd, 0, SEEK_END) != 0) {
|
|
|
|
// Error seeking.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
end = ftell(tmp_fd);
|
|
|
|
if (end == -1L) {
|
|
|
|
// Error getting end position.
|
|
|
|
return 1;
|
|
|
|
} else if (fseek(tmp_fd, 0, SEEK_SET) != 0) {
|
|
|
|
// Error seeking.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write file length.
|
2024-09-06 05:23:27 +00:00
|
|
|
u64 = (uint64_t)end;
|
2024-07-17 07:37:32 +00:00
|
|
|
simple_archiver_helper_64_bit_be(&u64);
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(8);
|
|
|
|
temp_to_write->size = 8;
|
|
|
|
memcpy(temp_to_write->buf, &u64, 8);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Write all previuosly set data before writing file.
|
|
|
|
simple_archiver_list_get(to_write, write_list_datas_fn, state->out_f);
|
|
|
|
|
|
|
|
simple_archiver_list_free(&to_write);
|
|
|
|
|
|
|
|
// Write file.
|
2024-07-17 08:22:09 +00:00
|
|
|
fprintf(stderr, "Writing compressed file: %s\n", file_info->filename);
|
2024-07-17 07:37:32 +00:00
|
|
|
do {
|
|
|
|
write_count = fread(write_buf, 1, 1024, tmp_fd);
|
|
|
|
if (write_count == 1024) {
|
|
|
|
fwrite(write_buf, 1, 1024, state->out_f);
|
|
|
|
} else if (write_count > 0) {
|
|
|
|
fwrite(write_buf, 1, write_count, state->out_f);
|
|
|
|
}
|
|
|
|
if (feof(tmp_fd)) {
|
|
|
|
break;
|
|
|
|
} else if (ferror(tmp_fd)) {
|
|
|
|
// Error.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
// Cleanup.
|
2024-07-29 07:31:10 +00:00
|
|
|
simple_archiver_helper_cleanup_FILE(&tmp_fd);
|
2024-07-17 07:37:32 +00:00
|
|
|
#endif
|
2024-07-16 07:16:58 +00:00
|
|
|
} else {
|
|
|
|
uint16_t u16;
|
|
|
|
uint64_t u64;
|
|
|
|
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t temp_size = strlen(file_info->filename);
|
|
|
|
if (temp_size > 0xFFFF) {
|
|
|
|
fprintf(stderr, "ERROR: Filename is too large to store!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
u16 = (uint16_t)temp_size;
|
2024-07-16 07:16:58 +00:00
|
|
|
|
|
|
|
// Write filename length.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(2);
|
|
|
|
temp_to_write->size = 2;
|
|
|
|
memcpy(temp_to_write->buf, &u16, 2);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Write filename.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(u16 + 1);
|
|
|
|
temp_to_write->size = u16 + 1;
|
|
|
|
memcpy(temp_to_write->buf, file_info->filename, u16 + 1);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Write flags.
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(4);
|
|
|
|
temp_to_write->size = 4;
|
2024-09-06 05:23:27 +00:00
|
|
|
for (size_t idx = 0; idx < temp_to_write->size; ++idx) {
|
2024-07-16 07:16:58 +00:00
|
|
|
((unsigned char *)temp_to_write->buf)[idx] = 0;
|
|
|
|
}
|
2024-07-18 05:02:15 +00:00
|
|
|
|
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
|
|
|
// Get file stats.
|
|
|
|
struct stat stat_buf;
|
|
|
|
memset(&stat_buf, 0, sizeof(struct stat));
|
|
|
|
int stat_fd = open(file_info->filename, O_RDONLY);
|
|
|
|
if (stat_fd == -1) {
|
|
|
|
// Error.
|
2024-07-26 07:01:39 +00:00
|
|
|
fprintf(stderr, "ERROR: Failed to get stat of \"%s\"!\n",
|
|
|
|
file_info->filename);
|
2024-07-18 05:02:15 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
int stat_status = fstat(stat_fd, &stat_buf);
|
|
|
|
close(stat_fd);
|
|
|
|
if (stat_status != 0) {
|
|
|
|
// Error.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((stat_buf.st_mode & S_IRUSR) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x2;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IWUSR) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x4;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IXUSR) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x8;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IRGRP) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x10;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IWGRP) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x20;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IXGRP) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x40;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IROTH) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x80;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IWOTH) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[1] |= 0x1;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IXOTH) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[1] |= 0x2;
|
|
|
|
}
|
2024-07-23 05:16:57 +00:00
|
|
|
#else
|
|
|
|
// Unsupported platform. Just set the permission bits for user.
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0xE;
|
2024-07-18 05:02:15 +00:00
|
|
|
#endif
|
|
|
|
|
2024-07-16 07:16:58 +00:00
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Write file length.
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(simple_archiver_helper_cleanup_FILE))) FILE *fd =
|
2024-07-16 07:16:58 +00:00
|
|
|
fopen(file_info->filename, "rb");
|
|
|
|
if (!fd) {
|
|
|
|
// Error.
|
|
|
|
return 1;
|
|
|
|
} else if (fseek(fd, 0, SEEK_END) != 0) {
|
|
|
|
// Error.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
long end = ftell(fd);
|
|
|
|
if (end == -1L) {
|
|
|
|
// Error.
|
|
|
|
return 1;
|
|
|
|
}
|
2024-09-06 05:23:27 +00:00
|
|
|
u64 = (uint64_t)end;
|
2024-07-16 07:16:58 +00:00
|
|
|
simple_archiver_helper_64_bit_be(&u64);
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(8);
|
|
|
|
temp_to_write->size = 8;
|
|
|
|
memcpy(temp_to_write->buf, &u64, 8);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
if (fseek(fd, 0, SEEK_SET) != 0) {
|
|
|
|
// Error.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write all previuosly set data before writing file.
|
|
|
|
simple_archiver_list_get(to_write, write_list_datas_fn, state->out_f);
|
|
|
|
|
|
|
|
simple_archiver_list_free(&to_write);
|
|
|
|
|
|
|
|
// Write file.
|
2024-07-17 08:22:09 +00:00
|
|
|
fprintf(stderr, "Writing file: %s\n", file_info->filename);
|
2024-07-16 07:16:58 +00:00
|
|
|
char buf[1024];
|
|
|
|
size_t ret;
|
|
|
|
do {
|
|
|
|
ret = fread(buf, 1, 1024, fd);
|
|
|
|
if (ret == 1024) {
|
|
|
|
fwrite(buf, 1, 1024, state->out_f);
|
|
|
|
} else if (ret > 0) {
|
|
|
|
fwrite(buf, 1, ret, state->out_f);
|
|
|
|
}
|
|
|
|
if (feof(fd)) {
|
|
|
|
break;
|
|
|
|
} else if (ferror(fd)) {
|
|
|
|
// Error.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// A symblic link.
|
2024-07-22 05:01:01 +00:00
|
|
|
uint16_t u16;
|
|
|
|
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t temp_size = strlen(file_info->filename);
|
|
|
|
if (temp_size > 0xFFFF) {
|
|
|
|
fprintf(stderr, "ERROR: Filename is too large to store!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
u16 = (uint16_t)temp_size;
|
2024-07-22 05:01:01 +00:00
|
|
|
|
|
|
|
// Write filename length.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(2);
|
|
|
|
temp_to_write->size = 2;
|
|
|
|
memcpy(temp_to_write->buf, &u16, 2);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Write filename.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(u16 + 1);
|
|
|
|
temp_to_write->size = u16 + 1;
|
|
|
|
memcpy(temp_to_write->buf, file_info->filename, u16 + 1);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Write flags.
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(4);
|
|
|
|
temp_to_write->size = 4;
|
2024-09-06 05:23:27 +00:00
|
|
|
for (size_t idx = 0; idx < temp_to_write->size; ++idx) {
|
2024-07-22 05:01:01 +00:00
|
|
|
((unsigned char *)temp_to_write->buf)[idx] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set "is symbolic link" flag.
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] = 1;
|
|
|
|
|
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
|
|
|
// Get file stats.
|
|
|
|
struct stat stat_buf;
|
|
|
|
memset(&stat_buf, 0, sizeof(struct stat));
|
|
|
|
int stat_status =
|
|
|
|
fstatat(AT_FDCWD, file_info->filename, &stat_buf, AT_SYMLINK_NOFOLLOW);
|
|
|
|
if (stat_status != 0) {
|
|
|
|
// Error.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((stat_buf.st_mode & S_IRUSR) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x2;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IWUSR) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x4;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IXUSR) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x8;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IRGRP) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x10;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IWGRP) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x20;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IXGRP) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x40;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IROTH) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0x80;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IWOTH) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[1] |= 0x1;
|
|
|
|
}
|
|
|
|
if ((stat_buf.st_mode & S_IXOTH) != 0) {
|
|
|
|
((unsigned char *)temp_to_write->buf)[1] |= 0x2;
|
|
|
|
}
|
2024-07-23 05:16:57 +00:00
|
|
|
#else
|
|
|
|
// Unsupported platform. Just set the permission bits for user.
|
|
|
|
((unsigned char *)temp_to_write->buf)[0] |= 0xE;
|
2024-07-22 05:01:01 +00:00
|
|
|
#endif
|
|
|
|
|
2024-07-24 05:31:38 +00:00
|
|
|
// Need to get abs_path for checking/setting a flag before storing flags.
|
2024-07-23 06:28:59 +00:00
|
|
|
// Get absolute path.
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(
|
|
|
|
simple_archiver_helper_cleanup_malloced))) void *abs_path = NULL;
|
2024-07-24 06:03:34 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
|
|
|
abs_path = realpath(file_info->filename, NULL);
|
|
|
|
#endif
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(
|
|
|
|
simple_archiver_helper_cleanup_malloced))) void *rel_path = NULL;
|
2024-07-24 05:31:38 +00:00
|
|
|
if (abs_path) {
|
2024-07-24 04:32:39 +00:00
|
|
|
// Get relative path.
|
|
|
|
// First get absolute path of link.
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(
|
|
|
|
simple_archiver_helper_cleanup_malloced))) void *link_abs_path =
|
2024-07-24 05:04:19 +00:00
|
|
|
filename_to_absolute_path(file_info->filename);
|
|
|
|
if (!link_abs_path) {
|
|
|
|
fprintf(stderr, "WARNING: Failed to get absolute path of link!\n");
|
2024-07-24 04:32:39 +00:00
|
|
|
} else {
|
2024-07-24 05:04:19 +00:00
|
|
|
// fprintf(stderr, "DEBUG: abs_path: %s\nDEBUG: link_abs_path: %s\n",
|
|
|
|
// (char*)abs_path, (char*)link_abs_path);
|
|
|
|
|
2024-07-24 04:32:39 +00:00
|
|
|
// Compare paths to get relative path.
|
|
|
|
// Get first non-common char.
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t idx;
|
|
|
|
size_t last_slash;
|
2024-07-24 04:32:39 +00:00
|
|
|
for (idx = 0, last_slash = 0;
|
2024-07-24 05:04:19 +00:00
|
|
|
idx < strlen(abs_path) && idx < strlen(link_abs_path); ++idx) {
|
2024-07-24 04:32:39 +00:00
|
|
|
if (((const char *)abs_path)[idx] !=
|
2024-07-24 05:04:19 +00:00
|
|
|
((const char *)link_abs_path)[idx]) {
|
2024-07-24 04:32:39 +00:00
|
|
|
break;
|
|
|
|
} else if (((const char *)abs_path)[idx] == '/') {
|
|
|
|
last_slash = idx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Get substrings of both paths.
|
2024-07-24 05:04:19 +00:00
|
|
|
char *link_substr = (char *)link_abs_path + last_slash;
|
2024-07-24 04:32:39 +00:00
|
|
|
char *dest_substr = (char *)abs_path + last_slash;
|
|
|
|
rel_path = malloc(strlen(dest_substr) + 1);
|
|
|
|
strncpy(rel_path, dest_substr, strlen(dest_substr) + 1);
|
|
|
|
// fprintf(stderr, "DEBUG: link_substr: %s\nDEBUG: dest_substr: %s\n",
|
|
|
|
// link_substr, dest_substr);
|
2024-07-24 05:04:19 +00:00
|
|
|
|
2024-07-24 04:32:39 +00:00
|
|
|
// Generate the relative path.
|
|
|
|
int has_slash = 0;
|
|
|
|
idx = 0;
|
|
|
|
do {
|
|
|
|
for (; link_substr[idx] != '/' && link_substr[idx] != 0; ++idx);
|
|
|
|
if (link_substr[idx] == 0) {
|
|
|
|
has_slash = 0;
|
|
|
|
} else {
|
|
|
|
has_slash = 1;
|
|
|
|
char *new_rel_path = malloc(strlen(rel_path) + 1 + 3);
|
|
|
|
new_rel_path[0] = '.';
|
|
|
|
new_rel_path[1] = '.';
|
|
|
|
new_rel_path[2] = '/';
|
|
|
|
strncpy(new_rel_path + 3, rel_path, strlen(rel_path) + 1);
|
|
|
|
free(rel_path);
|
|
|
|
rel_path = new_rel_path;
|
|
|
|
++idx;
|
|
|
|
}
|
|
|
|
} while (has_slash);
|
|
|
|
}
|
2024-07-24 05:31:38 +00:00
|
|
|
}
|
2024-07-24 04:32:39 +00:00
|
|
|
|
2024-07-24 05:31:38 +00:00
|
|
|
// Check if absolute path refers to one of the filenames.
|
|
|
|
if (abs_path && (state->parsed->flags & 0x20) == 0 &&
|
|
|
|
!simple_archiver_hash_map_get(state->map, abs_path,
|
|
|
|
strlen(abs_path) + 1)) {
|
|
|
|
// Is not a filename being archived, set preference to absolute path.
|
|
|
|
fprintf(stderr,
|
|
|
|
"NOTICE: abs_path exists, \"--no-abs-symlink\" not specified, "
|
|
|
|
"and link refers to file NOT in archive; preferring abs_path.\n");
|
|
|
|
((unsigned char *)temp_to_write->buf)[1] |= 0x4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store the 4 byte bit-flags for file.
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Store the absolute and relative paths.
|
|
|
|
if (!abs_path) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to get absolute path of link destination!\n");
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(2);
|
|
|
|
temp_to_write->size = 2;
|
|
|
|
memset(temp_to_write->buf, 0, 2);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
} else if ((state->parsed->flags & 0x20) == 0) {
|
|
|
|
// Write absolute path length.
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t temp_size = strlen(abs_path);
|
|
|
|
if (temp_size > 0xFFFF) {
|
|
|
|
fprintf(stderr, "ERROR: Absolute path name is too large!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
u16 = (uint16_t)temp_size;
|
2024-07-24 05:31:38 +00:00
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(2);
|
|
|
|
temp_to_write->size = 2;
|
|
|
|
memcpy(temp_to_write->buf, &u16, 2);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Write absolute path.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(u16 + 1);
|
|
|
|
temp_to_write->size = u16 + 1;
|
|
|
|
strncpy(temp_to_write->buf, abs_path, u16 + 1);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr,
|
|
|
|
"NOTICE: Not saving absolute path since \"--no-abs-symlink\" "
|
|
|
|
"was specified.\n");
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(2);
|
|
|
|
temp_to_write->size = 2;
|
|
|
|
memset(temp_to_write->buf, 0, 2);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
2024-07-23 06:28:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rel_path) {
|
|
|
|
// Write relative path length.
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t temp_size = strlen(rel_path);
|
|
|
|
if (temp_size > 0xFFFF) {
|
|
|
|
fprintf(stderr, "ERROR: Relative path name is too large!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
u16 = (uint16_t)temp_size;
|
2024-07-23 06:28:59 +00:00
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(2);
|
|
|
|
temp_to_write->size = 2;
|
|
|
|
memcpy(temp_to_write->buf, &u16, 2);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
|
|
|
|
// Write relative path.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(u16 + 1);
|
|
|
|
temp_to_write->size = u16 + 1;
|
|
|
|
strncpy(temp_to_write->buf, rel_path, u16 + 1);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
} else {
|
|
|
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
|
|
|
temp_to_write->buf = malloc(2);
|
|
|
|
temp_to_write->size = 2;
|
|
|
|
memset(temp_to_write->buf, 0, 2);
|
|
|
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
|
|
|
}
|
2024-07-22 05:01:01 +00:00
|
|
|
|
|
|
|
// Write all previously set data.
|
|
|
|
fprintf(stderr, "Writing symlink info: %s\n", file_info->filename);
|
2024-07-24 04:32:39 +00:00
|
|
|
if ((state->parsed->flags & 0x20) == 0) {
|
|
|
|
fprintf(stderr, " abs path: %s\n", (char *)abs_path);
|
|
|
|
}
|
2024-07-23 06:28:59 +00:00
|
|
|
fprintf(stderr, " rel path: %s\n", (char *)rel_path);
|
2024-07-22 05:01:01 +00:00
|
|
|
simple_archiver_list_get(to_write, write_list_datas_fn, state->out_f);
|
|
|
|
simple_archiver_list_free(&to_write);
|
2024-07-16 07:16:58 +00:00
|
|
|
}
|
|
|
|
|
2024-07-26 07:18:07 +00:00
|
|
|
char format_str[64];
|
|
|
|
snprintf(format_str, 64, FILE_COUNTS_OUTPUT_FORMAT_STR_1, state->digits,
|
|
|
|
state->digits);
|
|
|
|
fprintf(stderr, format_str, ++(state->count), state->max);
|
2024-07-16 07:16:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-07-24 05:05:05 +00:00
|
|
|
int filenames_to_abs_map_fn(void *data, void *ud) {
|
|
|
|
SDArchiverFileInfo *file_info = data;
|
2024-07-26 03:39:56 +00:00
|
|
|
void **ptr_array = ud;
|
|
|
|
SDArchiverHashMap **abs_filenames = ptr_array[0];
|
|
|
|
const char *user_cwd = ptr_array[1];
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(
|
|
|
|
simple_archiver_helper_cleanup_chdir_back))) char *original_cwd = NULL;
|
2024-07-26 04:17:11 +00:00
|
|
|
if (user_cwd) {
|
2024-07-26 04:23:51 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
2024-07-26 04:17:11 +00:00
|
|
|
original_cwd = realpath(".", NULL);
|
|
|
|
if (chdir(user_cwd)) {
|
|
|
|
return 1;
|
|
|
|
}
|
2024-07-26 04:23:51 +00:00
|
|
|
#endif
|
2024-07-26 04:17:11 +00:00
|
|
|
}
|
2024-07-24 05:05:05 +00:00
|
|
|
|
|
|
|
// Get combined full path to file.
|
|
|
|
char *fullpath = filename_to_absolute_path(file_info->filename);
|
2024-07-24 05:31:38 +00:00
|
|
|
if (!fullpath) {
|
|
|
|
return 1;
|
|
|
|
}
|
2024-07-24 05:05:05 +00:00
|
|
|
|
2024-07-29 07:31:10 +00:00
|
|
|
simple_archiver_hash_map_insert(
|
2024-09-09 02:25:00 +00:00
|
|
|
*abs_filenames, fullpath, fullpath, strlen(fullpath) + 1,
|
2024-07-29 07:31:10 +00:00
|
|
|
simple_archiver_helper_datastructure_cleanup_nop, NULL);
|
2024-07-24 05:05:05 +00:00
|
|
|
|
2024-07-24 05:31:38 +00:00
|
|
|
// Try putting all parent dirs up to current working directory.
|
|
|
|
// First get absolute path to current working directory.
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(
|
|
|
|
simple_archiver_helper_cleanup_malloced))) void *cwd_dirname = NULL;
|
2024-07-24 06:03:34 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
2024-07-26 04:17:11 +00:00
|
|
|
cwd_dirname = realpath(".", NULL);
|
2024-07-24 06:03:34 +00:00
|
|
|
#endif
|
2024-07-24 05:31:38 +00:00
|
|
|
if (!cwd_dirname) {
|
|
|
|
return 1;
|
|
|
|
}
|
2024-07-26 03:39:56 +00:00
|
|
|
// fprintf(stderr, "cwd_dirname: %s\n", (char*)cwd_dirname);
|
2024-07-24 05:31:38 +00:00
|
|
|
|
|
|
|
// Use copy of fullpath to avoid clobbering it.
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((
|
|
|
|
cleanup(simple_archiver_helper_cleanup_malloced))) void *fullpath_copy =
|
2024-07-24 05:31:38 +00:00
|
|
|
malloc(strlen(fullpath) + 1);
|
|
|
|
strncpy(fullpath_copy, fullpath, strlen(fullpath) + 1);
|
|
|
|
|
|
|
|
// Get dirnames.
|
|
|
|
char *prev = fullpath_copy;
|
|
|
|
char *fullpath_dirname;
|
|
|
|
while (1) {
|
|
|
|
fullpath_dirname = dirname(prev);
|
|
|
|
if (!fullpath_dirname || strlen(fullpath_dirname) <= strlen(cwd_dirname)) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
// Make and store copy of fullpath_dirname.
|
|
|
|
char *fullpath_dirname_copy = malloc(strlen(fullpath_dirname) + 1);
|
|
|
|
strncpy(fullpath_dirname_copy, fullpath_dirname,
|
|
|
|
strlen(fullpath_dirname) + 1);
|
|
|
|
simple_archiver_hash_map_insert(
|
2024-09-09 02:25:00 +00:00
|
|
|
*abs_filenames, fullpath_dirname_copy, fullpath_dirname_copy,
|
2024-07-29 07:31:10 +00:00
|
|
|
strlen(fullpath_dirname_copy) + 1,
|
|
|
|
simple_archiver_helper_datastructure_cleanup_nop, NULL);
|
2024-07-24 05:31:38 +00:00
|
|
|
}
|
|
|
|
prev = fullpath_dirname;
|
|
|
|
}
|
|
|
|
|
2024-07-24 05:05:05 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-07-18 05:39:01 +00:00
|
|
|
char *simple_archiver_error_to_string(enum SDArchiverStateReturns error) {
|
|
|
|
switch (error) {
|
|
|
|
case SDAS_SUCCESS:
|
|
|
|
return "SUCCESS";
|
|
|
|
case SDAS_HEADER_ALREADY_WRITTEN:
|
|
|
|
return "Header already written";
|
|
|
|
case SDAS_FAILED_TO_WRITE:
|
|
|
|
return "Failed to write";
|
|
|
|
case SDAS_NO_COMPRESSOR:
|
|
|
|
return "Compressor cmd is missing";
|
|
|
|
case SDAS_NO_DECOMPRESSOR:
|
|
|
|
return "Decompressor cmd is missing";
|
|
|
|
case SDAS_INVALID_PARSED_STATE:
|
|
|
|
return "Invalid parsed struct";
|
|
|
|
case SDAS_INVALID_FILE:
|
|
|
|
return "Invalid file";
|
|
|
|
case SDAS_INTERNAL_ERROR:
|
|
|
|
return "Internal error";
|
2024-07-24 05:05:05 +00:00
|
|
|
case SDAS_FAILED_TO_CREATE_MAP:
|
|
|
|
return "Failed to create set of filenames (internal error)";
|
2024-07-24 05:52:35 +00:00
|
|
|
case SDAS_FAILED_TO_EXTRACT_SYMLINK:
|
|
|
|
return "Failed to extract symlink (internal error)";
|
2024-07-26 03:39:56 +00:00
|
|
|
case SDAS_FAILED_TO_CHANGE_CWD:
|
|
|
|
return "Failed to change current working directory";
|
2024-07-18 05:39:01 +00:00
|
|
|
default:
|
|
|
|
return "Unknown error";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-16 07:16:58 +00:00
|
|
|
SDArchiverState *simple_archiver_init_state(const SDArchiverParsed *parsed) {
|
|
|
|
if (!parsed) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDArchiverState *state = malloc(sizeof(SDArchiverState));
|
|
|
|
state->flags = 0;
|
|
|
|
state->parsed = parsed;
|
|
|
|
state->out_f = NULL;
|
2024-07-24 05:05:05 +00:00
|
|
|
state->map = NULL;
|
2024-07-26 07:18:07 +00:00
|
|
|
state->count = 0;
|
|
|
|
state->max = 0;
|
|
|
|
state->digits = 10;
|
2024-07-16 07:16:58 +00:00
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void simple_archiver_free_state(SDArchiverState **state) {
|
|
|
|
if (state && *state) {
|
|
|
|
free(*state);
|
|
|
|
*state = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int simple_archiver_write_all(FILE *out_f, SDArchiverState *state,
|
|
|
|
const SDArchiverLinkedList *filenames) {
|
2024-07-24 05:05:05 +00:00
|
|
|
// First create a "set" of absolute paths to given filenames.
|
|
|
|
__attribute__((cleanup(simple_archiver_hash_map_free)))
|
|
|
|
SDArchiverHashMap *abs_filenames = simple_archiver_hash_map_init();
|
2024-07-26 03:39:56 +00:00
|
|
|
void **ptr_array = malloc(sizeof(void *) * 2);
|
|
|
|
ptr_array[0] = &abs_filenames;
|
|
|
|
ptr_array[1] = (void *)state->parsed->user_cwd;
|
|
|
|
if (simple_archiver_list_get(filenames, filenames_to_abs_map_fn, ptr_array)) {
|
|
|
|
free(ptr_array);
|
2024-07-24 05:05:05 +00:00
|
|
|
return SDAS_FAILED_TO_CREATE_MAP;
|
|
|
|
}
|
2024-07-26 03:39:56 +00:00
|
|
|
free(ptr_array);
|
2024-07-24 05:05:05 +00:00
|
|
|
|
2024-07-16 07:16:58 +00:00
|
|
|
if (fwrite("SIMPLE_ARCHIVE_VER", 1, 18, out_f) != 18) {
|
|
|
|
return SDAS_FAILED_TO_WRITE;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t u16 = 0;
|
|
|
|
|
|
|
|
// No need to convert to big-endian for version 0.
|
|
|
|
// simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
|
|
|
|
if (fwrite(&u16, 2, 1, out_f) != 1) {
|
|
|
|
return SDAS_FAILED_TO_WRITE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->parsed->compressor && !state->parsed->decompressor) {
|
|
|
|
return SDAS_NO_DECOMPRESSOR;
|
|
|
|
} else if (!state->parsed->compressor && state->parsed->decompressor) {
|
|
|
|
return SDAS_NO_COMPRESSOR;
|
|
|
|
} else if (state->parsed->compressor && state->parsed->decompressor) {
|
|
|
|
// Write the four flag bytes with first bit set.
|
|
|
|
unsigned char c = 1;
|
|
|
|
if (fwrite(&c, 1, 1, out_f) != 1) {
|
|
|
|
return SDAS_FAILED_TO_WRITE;
|
|
|
|
}
|
|
|
|
c = 0;
|
2024-09-06 05:23:27 +00:00
|
|
|
for (size_t i = 0; i < 3; ++i) {
|
2024-07-16 07:16:58 +00:00
|
|
|
if (fwrite(&c, 1, 1, out_f) != 1) {
|
|
|
|
return SDAS_FAILED_TO_WRITE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// De/compressor bytes.
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t temp_size = strlen(state->parsed->compressor);
|
|
|
|
if (temp_size > 0xFFFF) {
|
|
|
|
fprintf(stderr, "ERROR: Compressor cmd string is too large!\n");
|
|
|
|
return SDAS_NO_COMPRESSOR;
|
|
|
|
}
|
|
|
|
u16 = (uint16_t)temp_size;
|
2024-07-16 07:16:58 +00:00
|
|
|
// To big-endian.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
// Write the size in big-endian.
|
|
|
|
if (fwrite(&u16, 2, 1, out_f) != 1) {
|
|
|
|
return SDAS_FAILED_TO_WRITE;
|
|
|
|
}
|
|
|
|
// From big-endian.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
// Write the compressor cmd including the NULL at the end of the string.
|
|
|
|
if (fwrite(state->parsed->compressor, 1, u16 + 1, out_f) !=
|
|
|
|
(size_t)u16 + 1) {
|
|
|
|
return SDAS_FAILED_TO_WRITE;
|
|
|
|
}
|
|
|
|
|
2024-09-06 05:23:27 +00:00
|
|
|
temp_size = strlen(state->parsed->decompressor);
|
|
|
|
if (temp_size > 0xFFFF) {
|
|
|
|
fprintf(stderr, "ERROR: Decompressor cmd string is too large!\n");
|
|
|
|
return SDAS_NO_DECOMPRESSOR;
|
|
|
|
}
|
|
|
|
u16 = (uint16_t)temp_size;
|
2024-07-16 07:16:58 +00:00
|
|
|
// To big-endian.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
// Write the size in big-endian.
|
|
|
|
if (fwrite(&u16, 2, 1, out_f) != 1) {
|
|
|
|
return SDAS_FAILED_TO_WRITE;
|
|
|
|
}
|
|
|
|
// From big-endian.
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
// Write the decompressor cmd including the NULL at the end of the string.
|
|
|
|
if (fwrite(state->parsed->decompressor, 1, u16 + 1, out_f) !=
|
|
|
|
(size_t)u16 + 1) {
|
|
|
|
return SDAS_FAILED_TO_WRITE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Write the four flag bytes with first bit NOT set.
|
|
|
|
unsigned char c = 0;
|
2024-09-06 05:23:27 +00:00
|
|
|
for (size_t i = 0; i < 4; ++i) {
|
2024-07-16 07:16:58 +00:00
|
|
|
if (fwrite(&c, 1, 1, out_f) != 1) {
|
|
|
|
return SDAS_FAILED_TO_WRITE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write file count.
|
|
|
|
{
|
2024-09-06 05:23:27 +00:00
|
|
|
if (filenames->count > 0xFFFFFFFF) {
|
|
|
|
fprintf(stderr, "ERROR: Filenames count is too large!\n");
|
|
|
|
return SDAS_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
uint32_t u32 = (uint32_t)filenames->count;
|
2024-07-16 07:16:58 +00:00
|
|
|
simple_archiver_helper_32_bit_be(&u32);
|
|
|
|
if (fwrite(&u32, 1, 4, out_f) != 4) {
|
|
|
|
return SDAS_FAILED_TO_WRITE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate over files in list to write.
|
2024-07-16 07:44:54 +00:00
|
|
|
state->count = 0;
|
|
|
|
state->max = filenames->count;
|
2024-07-16 07:16:58 +00:00
|
|
|
state->out_f = out_f;
|
2024-07-24 05:05:05 +00:00
|
|
|
state->map = abs_filenames;
|
2024-07-26 07:18:07 +00:00
|
|
|
state->digits = simple_archiver_helper_num_digits(state->max);
|
2024-07-16 07:44:54 +00:00
|
|
|
fprintf(stderr, "Begin archiving...\n");
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(
|
|
|
|
simple_archiver_helper_cleanup_chdir_back))) char *original_cwd = NULL;
|
2024-07-26 04:17:11 +00:00
|
|
|
if (state->parsed->user_cwd) {
|
2024-07-26 04:23:51 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
2024-07-26 04:17:11 +00:00
|
|
|
original_cwd = realpath(".", NULL);
|
|
|
|
if (chdir(state->parsed->user_cwd)) {
|
|
|
|
return 1;
|
|
|
|
}
|
2024-07-26 04:23:51 +00:00
|
|
|
#endif
|
2024-07-26 04:17:11 +00:00
|
|
|
}
|
2024-07-26 07:18:07 +00:00
|
|
|
char format_str[64];
|
|
|
|
snprintf(format_str, 64, FILE_COUNTS_OUTPUT_FORMAT_STR_1, state->digits,
|
|
|
|
state->digits);
|
|
|
|
fprintf(stderr, format_str, state->count, state->max);
|
2024-07-16 07:16:58 +00:00
|
|
|
if (simple_archiver_list_get(filenames, write_files_fn, state)) {
|
|
|
|
// Error occurred.
|
2024-07-19 02:29:14 +00:00
|
|
|
fprintf(stderr, "Error ocurred writing file(s) to archive.\n");
|
|
|
|
return SDAS_FAILED_TO_WRITE;
|
2024-07-16 07:16:58 +00:00
|
|
|
}
|
|
|
|
state->out_f = NULL;
|
|
|
|
|
2024-07-16 07:44:54 +00:00
|
|
|
fprintf(stderr, "End archiving.\n");
|
2024-07-16 07:16:58 +00:00
|
|
|
return SDAS_SUCCESS;
|
|
|
|
}
|
2024-07-17 04:30:05 +00:00
|
|
|
|
2024-07-18 04:16:24 +00:00
|
|
|
int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
|
|
|
|
const SDArchiverState *state) {
|
2024-07-17 04:30:05 +00:00
|
|
|
unsigned char buf[1024];
|
|
|
|
memset(buf, 0, 1024);
|
|
|
|
uint16_t u16;
|
|
|
|
uint32_t u32;
|
|
|
|
uint64_t u64;
|
2024-07-17 04:35:04 +00:00
|
|
|
int is_compressed = 0;
|
2024-07-17 04:30:05 +00:00
|
|
|
|
|
|
|
if (fread(buf, 1, 18, in_f) != 18) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
} else if (memcmp(buf, "SIMPLE_ARCHIVE_VER", 18) != 0) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
} else if (fread(buf, 1, 2, in_f) != 2) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
} else if (buf[0] != 0 || buf[1] != 0) {
|
|
|
|
// Version is not zero.
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
} else if (fread(buf, 1, 4, in_f) != 4) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
|
2024-07-26 03:39:56 +00:00
|
|
|
if (do_extract && state->parsed->user_cwd) {
|
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
|
|
|
if (chdir(state->parsed->user_cwd)) {
|
|
|
|
return SDAS_FAILED_TO_CHANGE_CWD;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(
|
|
|
|
simple_archiver_helper_cleanup_malloced))) void *decompressor_cmd = NULL;
|
2024-07-18 04:16:24 +00:00
|
|
|
|
2024-07-17 04:30:05 +00:00
|
|
|
if ((buf[0] & 1) != 0) {
|
|
|
|
fprintf(stderr, "De/compressor flag is set.\n");
|
2024-07-17 04:35:04 +00:00
|
|
|
is_compressed = 1;
|
2024-07-17 04:30:05 +00:00
|
|
|
|
|
|
|
// Read compressor data.
|
|
|
|
if (fread(&u16, 2, 1, in_f) != 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
fprintf(stderr, "Compressor size is %u\n", u16);
|
|
|
|
if (u16 < 1024) {
|
|
|
|
if (fread(buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
buf[1023] = 0;
|
|
|
|
fprintf(stderr, "Compressor cmd: %s\n", buf);
|
|
|
|
} else {
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((
|
|
|
|
cleanup(simple_archiver_helper_cleanup_malloced))) void *heap_buf =
|
2024-07-17 04:30:05 +00:00
|
|
|
malloc(u16 + 1);
|
|
|
|
unsigned char *uc_heap_buf = heap_buf;
|
|
|
|
if (fread(uc_heap_buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
uc_heap_buf[u16 - 1] = 0;
|
|
|
|
fprintf(stderr, "Compressor cmd: %s\n", uc_heap_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read decompressor data.
|
|
|
|
if (fread(&u16, 2, 1, in_f) != 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
|
|
|
fprintf(stderr, "Decompressor size is %u\n", u16);
|
|
|
|
if (u16 < 1024) {
|
|
|
|
if (fread(buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
buf[1023] = 0;
|
|
|
|
fprintf(stderr, "Decompressor cmd: %s\n", buf);
|
2024-07-18 04:16:24 +00:00
|
|
|
decompressor_cmd = malloc(u16 + 1);
|
|
|
|
memcpy((char *)decompressor_cmd, buf, u16 + 1);
|
|
|
|
((char *)decompressor_cmd)[u16] = 0;
|
2024-07-17 04:30:05 +00:00
|
|
|
} else {
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((
|
|
|
|
cleanup(simple_archiver_helper_cleanup_malloced))) void *heap_buf =
|
2024-07-17 04:30:05 +00:00
|
|
|
malloc(u16 + 1);
|
|
|
|
unsigned char *uc_heap_buf = heap_buf;
|
|
|
|
if (fread(uc_heap_buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
uc_heap_buf[u16 - 1] = 0;
|
|
|
|
fprintf(stderr, "Decompressor cmd: %s\n", uc_heap_buf);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "De/compressor flag is NOT set.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fread(&u32, 1, 4, in_f) != 4) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
simple_archiver_helper_32_bit_be(&u32);
|
|
|
|
fprintf(stderr, "File count is %u\n", u32);
|
|
|
|
|
2024-07-26 07:18:07 +00:00
|
|
|
const uint32_t size = u32;
|
2024-09-06 05:23:27 +00:00
|
|
|
const size_t digits = simple_archiver_helper_num_digits(size);
|
2024-07-26 07:18:07 +00:00
|
|
|
char format_str[128];
|
|
|
|
snprintf(format_str, 128, FILE_COUNTS_OUTPUT_FORMAT_STR_0, digits, digits);
|
2024-07-18 04:16:24 +00:00
|
|
|
int skip = 0;
|
2024-07-18 06:30:05 +00:00
|
|
|
__attribute__((cleanup(simple_archiver_hash_map_free)))
|
|
|
|
SDArchiverHashMap *hash_map = NULL;
|
2024-07-18 06:49:22 +00:00
|
|
|
if (state && state->parsed->working_files &&
|
|
|
|
state->parsed->working_files[0] != NULL) {
|
2024-07-18 06:30:05 +00:00
|
|
|
hash_map = simple_archiver_hash_map_init();
|
|
|
|
for (char **iter = state->parsed->working_files; *iter != NULL; ++iter) {
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t len = strlen(*iter) + 1;
|
2024-07-18 06:30:05 +00:00
|
|
|
char *key = malloc(len);
|
|
|
|
memcpy(key, *iter, len);
|
|
|
|
key[len - 1] = 0;
|
2024-07-29 07:31:10 +00:00
|
|
|
simple_archiver_hash_map_insert(
|
2024-09-09 02:25:00 +00:00
|
|
|
hash_map, key, key, len,
|
2024-07-29 07:31:10 +00:00
|
|
|
simple_archiver_helper_datastructure_cleanup_nop, NULL);
|
2024-07-18 06:32:48 +00:00
|
|
|
// fprintf(stderr, "\"%s\" put in map\n", key);
|
2024-07-18 06:30:05 +00:00
|
|
|
}
|
|
|
|
}
|
2024-07-17 04:30:05 +00:00
|
|
|
for (uint32_t idx = 0; idx < size; ++idx) {
|
2024-07-26 07:18:07 +00:00
|
|
|
fprintf(stderr, format_str, idx + 1, size);
|
2024-07-17 04:30:05 +00:00
|
|
|
if (feof(in_f) || ferror(in_f)) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
} else if (fread(&u16, 2, 1, in_f) != 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(
|
|
|
|
simple_archiver_helper_cleanup_malloced))) void *out_f_name = NULL;
|
|
|
|
__attribute__((cleanup(simple_archiver_helper_cleanup_FILE))) FILE *out_f =
|
|
|
|
NULL;
|
2024-07-17 04:30:05 +00:00
|
|
|
if (u16 < 1024) {
|
|
|
|
if (fread(buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
buf[1023] = 0;
|
|
|
|
fprintf(stderr, " Filename: %s\n", buf);
|
2024-07-18 04:16:24 +00:00
|
|
|
if (do_extract) {
|
|
|
|
if ((state->parsed->flags & 0x8) == 0) {
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(simple_archiver_helper_cleanup_FILE)))
|
|
|
|
FILE *test_fd = fopen((const char *)buf, "rb");
|
2024-07-18 04:16:24 +00:00
|
|
|
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) {
|
2024-07-18 05:02:15 +00:00
|
|
|
out_f_name = malloc(strlen((const char *)buf) + 1);
|
|
|
|
memcpy(out_f_name, buf, strlen((const char *)buf) + 1);
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
|
|
|
}
|
2024-07-17 04:30:05 +00:00
|
|
|
} else {
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((
|
|
|
|
cleanup(simple_archiver_helper_cleanup_malloced))) void *heap_buf =
|
2024-07-17 04:30:05 +00:00
|
|
|
malloc(u16 + 1);
|
|
|
|
unsigned char *uc_heap_buf = heap_buf;
|
|
|
|
if (fread(uc_heap_buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
uc_heap_buf[u16 - 1] = 0;
|
|
|
|
fprintf(stderr, " Filename: %s\n", uc_heap_buf);
|
2024-07-18 04:16:24 +00:00
|
|
|
if (do_extract) {
|
|
|
|
if ((state->parsed->flags & 0x8) == 0) {
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(simple_archiver_helper_cleanup_FILE)))
|
|
|
|
FILE *test_fd = fopen((const char *)buf, "rb");
|
2024-07-18 04:16:24 +00:00
|
|
|
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) {
|
2024-07-18 05:02:15 +00:00
|
|
|
out_f_name = malloc(strlen((const char *)buf) + 1);
|
|
|
|
memcpy(out_f_name, buf, strlen((const char *)buf) + 1);
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
|
|
|
}
|
2024-07-17 04:30:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fread(buf, 1, 4, in_f) != 4) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
|
2024-09-06 05:23:27 +00:00
|
|
|
mode_t permissions = 0;
|
2024-07-18 05:02:15 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
|
|
|
|
2024-07-18 06:57:45 +00:00
|
|
|
if (do_extract == 0) {
|
|
|
|
fprintf(stderr, " Permissions: ");
|
|
|
|
}
|
|
|
|
|
2024-07-18 05:02:15 +00:00
|
|
|
if ((buf[0] & 0x2) != 0) {
|
|
|
|
permissions |= S_IRUSR;
|
2024-07-18 06:57:45 +00:00
|
|
|
if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "r");
|
|
|
|
}
|
|
|
|
} else if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "-");
|
2024-07-18 05:02:15 +00:00
|
|
|
}
|
|
|
|
if ((buf[0] & 0x4) != 0) {
|
|
|
|
permissions |= S_IWUSR;
|
2024-07-18 06:57:45 +00:00
|
|
|
if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "w");
|
|
|
|
}
|
|
|
|
} else if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "-");
|
2024-07-18 05:02:15 +00:00
|
|
|
}
|
|
|
|
if ((buf[0] & 0x8) != 0) {
|
|
|
|
permissions |= S_IXUSR;
|
2024-07-18 06:57:45 +00:00
|
|
|
if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "x");
|
|
|
|
}
|
|
|
|
} else if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "-");
|
2024-07-18 05:02:15 +00:00
|
|
|
}
|
|
|
|
if ((buf[0] & 0x10) != 0) {
|
|
|
|
permissions |= S_IRGRP;
|
2024-07-18 06:57:45 +00:00
|
|
|
if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "r");
|
|
|
|
}
|
|
|
|
} else if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "-");
|
2024-07-18 05:02:15 +00:00
|
|
|
}
|
|
|
|
if ((buf[0] & 0x20) != 0) {
|
|
|
|
permissions |= S_IWGRP;
|
2024-07-18 06:57:45 +00:00
|
|
|
if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "w");
|
|
|
|
}
|
|
|
|
} else if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "-");
|
2024-07-18 05:02:15 +00:00
|
|
|
}
|
|
|
|
if ((buf[0] & 0x40) != 0) {
|
|
|
|
permissions |= S_IXGRP;
|
2024-07-18 06:57:45 +00:00
|
|
|
if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "x");
|
|
|
|
}
|
|
|
|
} else if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "-");
|
2024-07-18 05:02:15 +00:00
|
|
|
}
|
|
|
|
if ((buf[0] & 0x80) != 0) {
|
|
|
|
permissions |= S_IROTH;
|
2024-07-18 06:57:45 +00:00
|
|
|
if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "r");
|
|
|
|
}
|
|
|
|
} else if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "-");
|
2024-07-18 05:02:15 +00:00
|
|
|
}
|
|
|
|
if ((buf[1] & 0x1) != 0) {
|
|
|
|
permissions |= S_IWOTH;
|
2024-07-18 06:57:45 +00:00
|
|
|
if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "w");
|
|
|
|
}
|
|
|
|
} else if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "-");
|
2024-07-18 05:02:15 +00:00
|
|
|
}
|
|
|
|
if ((buf[1] & 0x2) != 0) {
|
|
|
|
permissions |= S_IXOTH;
|
2024-07-18 06:57:45 +00:00
|
|
|
if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "x");
|
|
|
|
}
|
|
|
|
} else if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "-");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (do_extract == 0) {
|
|
|
|
fprintf(stderr, "\n");
|
2024-07-18 05:02:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2024-07-17 04:30:05 +00:00
|
|
|
if ((buf[0] & 1) == 0) {
|
|
|
|
// Not a sybolic link.
|
|
|
|
if (fread(&u64, 8, 1, in_f) != 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
simple_archiver_helper_64_bit_be(&u64);
|
2024-07-17 04:35:04 +00:00
|
|
|
if (is_compressed) {
|
|
|
|
fprintf(stderr, " File size (compressed): %lu\n", u64);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, " File size: %lu\n", u64);
|
|
|
|
}
|
2024-07-18 04:16:24 +00:00
|
|
|
|
2024-07-18 06:30:05 +00:00
|
|
|
int skip_due_to_map = 0;
|
|
|
|
if (hash_map != NULL && out_f_name) {
|
|
|
|
if (simple_archiver_hash_map_get(hash_map, out_f_name,
|
|
|
|
strlen(out_f_name) + 1) == NULL) {
|
|
|
|
skip_due_to_map = 1;
|
|
|
|
fprintf(stderr, "Skipping not specified in args...\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (do_extract && !skip && !skip_due_to_map) {
|
2024-07-18 04:16:24 +00:00
|
|
|
fprintf(stderr, " Extracting...\n");
|
2024-07-18 05:17:50 +00:00
|
|
|
|
2024-07-18 06:30:05 +00:00
|
|
|
simple_archiver_helper_make_dirs((const char *)out_f_name);
|
|
|
|
out_f = fopen(out_f_name, "wb");
|
2024-07-19 02:29:14 +00:00
|
|
|
__attribute__((
|
|
|
|
cleanup(cleanup_temp_filename_delete))) void **ptrs_array =
|
|
|
|
malloc(sizeof(void *) * 2);
|
|
|
|
ptrs_array[0] = out_f_name;
|
|
|
|
ptrs_array[1] = &out_f;
|
2024-07-18 04:33:35 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
2024-07-18 05:17:50 +00:00
|
|
|
if (is_compressed) {
|
2024-07-19 03:13:54 +00:00
|
|
|
// Handle SIGPIPE.
|
|
|
|
signal(SIGPIPE, handle_sig_pipe);
|
|
|
|
|
2024-07-18 05:17:50 +00:00
|
|
|
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]);
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 05:17:50 +00:00
|
|
|
} 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]);
|
2024-07-18 04:16:24 +00:00
|
|
|
close(pipe_into_cmd[1]);
|
|
|
|
close(pipe_outof_cmd[0]);
|
2024-07-18 05:17:50 +00:00
|
|
|
close(pipe_outof_cmd[1]);
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 05:17:50 +00:00
|
|
|
} 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]);
|
2024-07-18 04:16:24 +00:00
|
|
|
close(pipe_into_cmd[1]);
|
|
|
|
close(pipe_outof_cmd[0]);
|
2024-07-18 05:17:50 +00:00
|
|
|
close(pipe_outof_cmd[1]);
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
|
|
|
|
2024-07-18 05:17:50 +00:00
|
|
|
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]);
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(
|
|
|
|
stderr,
|
|
|
|
"WARNING: Failed to start decompressor cmd! Invalid cmd?\n");
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 05:17:50 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (simple_archiver_de_compress(pipe_into_cmd, pipe_outof_cmd,
|
|
|
|
decompressor_cmd,
|
|
|
|
&decompressor_pid) != 0) {
|
|
|
|
// Failed to spawn compressor.
|
|
|
|
close(pipe_into_cmd[1]);
|
|
|
|
close(pipe_outof_cmd[0]);
|
2024-07-19 02:29:14 +00:00
|
|
|
fprintf(
|
|
|
|
stderr,
|
|
|
|
"WARNING: Failed to start decompressor cmd! Invalid cmd?\n");
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 05:17:50 +00:00
|
|
|
}
|
|
|
|
}
|
2024-07-18 04:16:24 +00:00
|
|
|
|
2024-07-18 05:17:50 +00:00
|
|
|
// Close unnecessary pipe fds on this end of the transfer.
|
|
|
|
close(pipe_into_cmd[0]);
|
|
|
|
close(pipe_outof_cmd[1]);
|
|
|
|
|
2024-07-19 02:29:14 +00:00
|
|
|
int decompressor_status;
|
|
|
|
int decompressor_return_val;
|
|
|
|
int decompressor_ret =
|
|
|
|
waitpid(decompressor_pid, &decompressor_status, WNOHANG);
|
|
|
|
if (decompressor_ret == decompressor_pid) {
|
|
|
|
// Status is available.
|
|
|
|
if (WIFEXITED(decompressor_status)) {
|
|
|
|
decompressor_return_val = WEXITSTATUS(decompressor_status);
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Exec failed (exec exit code %d)! Invalid "
|
|
|
|
"decompressor cmd?\n",
|
|
|
|
decompressor_return_val);
|
|
|
|
return SDAS_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
} else if (decompressor_ret == 0) {
|
|
|
|
// Probably still running, continue on.
|
|
|
|
} else {
|
|
|
|
// Error.
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Exec failed (exec exit code unknown)! Invalid "
|
|
|
|
"decompressor cmd?\n");
|
|
|
|
return SDAS_INTERNAL_ERROR;
|
|
|
|
}
|
|
|
|
|
2024-07-18 05:17:50 +00:00
|
|
|
uint64_t compressed_file_size = u64;
|
|
|
|
int write_again = 0;
|
|
|
|
int write_pipe_done = 0;
|
|
|
|
int read_pipe_done = 0;
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t fread_ret;
|
2024-07-18 05:17:50 +00:00
|
|
|
char recv_buf[1024];
|
|
|
|
size_t amount_to_read;
|
|
|
|
while (!write_pipe_done || !read_pipe_done) {
|
2024-07-19 03:13:54 +00:00
|
|
|
if (is_sig_pipe_occurred) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to write to decompressor (SIGPIPE)! "
|
|
|
|
"Invalid decompressor cmd?\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-07-18 05:17:50 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
2024-07-18 05:17:50 +00:00
|
|
|
|
|
|
|
// Send over pipe to decompressor.
|
2024-07-18 04:16:24 +00:00
|
|
|
if (fread_ret > 0) {
|
2024-07-18 05:17:50 +00:00
|
|
|
ssize_t write_ret = write(pipe_into_cmd[1], buf, fread_ret);
|
2024-09-06 05:23:27 +00:00
|
|
|
if (write_ret > 0 && (size_t)write_ret == fread_ret) {
|
2024-07-18 05:17:50 +00:00
|
|
|
// 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.
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to write to decompressor! Invalid "
|
|
|
|
"decompressor cmd?\n");
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 05:17:50 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Should be unreachable, error.
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to write to decompressor! Invalid "
|
|
|
|
"decompressor cmd?\n");
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 05:17:50 +00:00
|
|
|
}
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-18 05:17:50 +00:00
|
|
|
// 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) {
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t fwrite_ret =
|
|
|
|
fwrite(recv_buf, 1, (size_t)read_ret, out_f);
|
2024-07-18 05:17:50 +00:00
|
|
|
if (fwrite_ret == (size_t)read_ret) {
|
|
|
|
// Success.
|
|
|
|
} else if (ferror(out_f)) {
|
|
|
|
// Error.
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to read from decompressor! Invalid "
|
|
|
|
"decompressor cmd?\n");
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 05:17:50 +00:00
|
|
|
} else {
|
|
|
|
// Invalid state, error.
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to read from decompressor! Invalid "
|
|
|
|
"decompressor cmd?\n");
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
2024-07-18 05:17:50 +00:00
|
|
|
} else if (read_ret == -1) {
|
2024-07-18 04:16:24 +00:00
|
|
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
2024-07-18 05:17:50 +00:00
|
|
|
// No bytes to read yet.
|
2024-07-18 04:16:24 +00:00
|
|
|
} else {
|
|
|
|
// Error.
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to read from decompressor! Invalid "
|
|
|
|
"decompressor cmd?\n");
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
2024-07-18 05:17:50 +00:00
|
|
|
} else if (read_ret == 0) {
|
|
|
|
// EOF.
|
|
|
|
read_pipe_done = 1;
|
|
|
|
close(pipe_outof_cmd[0]);
|
2024-07-29 07:31:10 +00:00
|
|
|
simple_archiver_helper_cleanup_FILE(&out_f);
|
2024-07-18 04:16:24 +00:00
|
|
|
} else {
|
2024-07-18 05:17:50 +00:00
|
|
|
// Invalid state (unreachable?), error.
|
2024-07-19 03:13:54 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to read from decompressor! Invalid "
|
|
|
|
"decompressor cmd?\n");
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-19 03:13:54 +00:00
|
|
|
if (is_sig_pipe_occurred) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"WARNING: Failed to write to decompressor (SIGPIPE)! "
|
|
|
|
"Invalid decompressor cmd?\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-07-18 05:17:50 +00:00
|
|
|
waitpid(decompressor_pid, NULL, 0);
|
|
|
|
} else {
|
|
|
|
uint64_t compressed_file_size = u64;
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t fread_ret;
|
2024-07-18 05:17:50 +00:00
|
|
|
while (compressed_file_size != 0) {
|
|
|
|
if (compressed_file_size > 1024) {
|
|
|
|
fread_ret = fread(buf, 1, 1024, in_f);
|
|
|
|
if (ferror(in_f)) {
|
2024-07-18 04:16:24 +00:00
|
|
|
// Error.
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
2024-07-18 05:17:50 +00:00
|
|
|
fwrite(buf, 1, fread_ret, out_f);
|
|
|
|
if (ferror(out_f)) {
|
2024-07-18 04:16:24 +00:00
|
|
|
// Error.
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
2024-07-18 05:17:50 +00:00
|
|
|
compressed_file_size -= fread_ret;
|
2024-07-18 04:16:24 +00:00
|
|
|
} else {
|
2024-07-18 05:17:50 +00:00
|
|
|
fread_ret = fread(buf, 1, compressed_file_size, in_f);
|
|
|
|
if (ferror(in_f)) {
|
|
|
|
// Error.
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 05:17:50 +00:00
|
|
|
}
|
|
|
|
fwrite(buf, 1, fread_ret, out_f);
|
|
|
|
if (ferror(out_f)) {
|
|
|
|
// Error.
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 05:17:50 +00:00
|
|
|
}
|
|
|
|
compressed_file_size -= fread_ret;
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-18 05:02:15 +00:00
|
|
|
if (chmod((const char *)out_f_name, permissions) == -1) {
|
|
|
|
// Error.
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 05:02:15 +00:00
|
|
|
}
|
|
|
|
|
2024-07-19 02:29:14 +00:00
|
|
|
ptrs_array[0] = NULL;
|
2024-07-18 04:16:24 +00:00
|
|
|
fprintf(stderr, " Extracted.\n");
|
2024-07-18 04:33:35 +00:00
|
|
|
#endif
|
2024-07-18 04:16:24 +00:00
|
|
|
} else {
|
|
|
|
while (u64 != 0) {
|
|
|
|
if (u64 > 1024) {
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t read_ret = fread(buf, 1, 1024, in_f);
|
2024-07-18 04:16:24 +00:00
|
|
|
if (read_ret > 0) {
|
|
|
|
u64 -= read_ret;
|
|
|
|
} else if (ferror(in_f)) {
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
|
|
|
} else {
|
2024-09-06 05:23:27 +00:00
|
|
|
size_t read_ret = fread(buf, 1, u64, in_f);
|
2024-07-18 04:16:24 +00:00
|
|
|
if (read_ret > 0) {
|
|
|
|
u64 -= read_ret;
|
|
|
|
} else if (ferror(in_f)) {
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_INTERNAL_ERROR;
|
2024-07-18 04:16:24 +00:00
|
|
|
}
|
2024-07-17 04:30:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Is a symbolic link.
|
2024-07-24 05:31:38 +00:00
|
|
|
|
|
|
|
int abs_preferred = (buf[1] & 0x4) != 0 ? 1 : 0;
|
2024-07-24 05:52:35 +00:00
|
|
|
fprintf(stderr, " Absolute path is %s\n",
|
2024-07-24 05:31:38 +00:00
|
|
|
(abs_preferred ? "preferred" : "NOT preferred"));
|
|
|
|
|
2024-07-29 07:31:10 +00:00
|
|
|
__attribute__((cleanup(
|
|
|
|
simple_archiver_helper_cleanup_malloced))) void *abs_path = NULL;
|
|
|
|
__attribute__((cleanup(
|
|
|
|
simple_archiver_helper_cleanup_malloced))) void *rel_path = NULL;
|
2024-07-24 05:52:35 +00:00
|
|
|
|
2024-07-17 04:30:05 +00:00
|
|
|
if (fread(&u16, 2, 1, in_f) != 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
2024-07-22 05:01:01 +00:00
|
|
|
if (u16 == 0) {
|
|
|
|
fprintf(stderr, " Link does not have absolute path.\n");
|
|
|
|
} else if (u16 < 1024) {
|
2024-07-17 04:30:05 +00:00
|
|
|
if (fread(buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
buf[1023] = 0;
|
|
|
|
fprintf(stderr, " Link absolute path: %s\n", buf);
|
2024-07-24 05:52:35 +00:00
|
|
|
abs_path = malloc((size_t)u16 + 1);
|
|
|
|
strncpy(abs_path, (char *)buf, (size_t)u16 + 1);
|
2024-07-17 04:30:05 +00:00
|
|
|
} else {
|
2024-07-24 05:52:35 +00:00
|
|
|
abs_path = malloc(u16 + 1);
|
|
|
|
if (fread(abs_path, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
2024-07-17 04:30:05 +00:00
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
2024-07-24 05:52:35 +00:00
|
|
|
((char *)abs_path)[u16 - 1] = 0;
|
|
|
|
fprintf(stderr, " Link absolute path: %s\n", (char *)abs_path);
|
2024-07-17 04:30:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fread(&u16, 2, 1, in_f) != 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
simple_archiver_helper_16_bit_be(&u16);
|
2024-07-22 05:01:01 +00:00
|
|
|
if (u16 == 0) {
|
|
|
|
fprintf(stderr, " Link does not have relative path.\n");
|
|
|
|
} else if (u16 < 1024) {
|
2024-07-17 04:30:05 +00:00
|
|
|
if (fread(buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
|
|
|
buf[1023] = 0;
|
|
|
|
fprintf(stderr, " Link relative path: %s\n", buf);
|
2024-07-24 05:52:35 +00:00
|
|
|
rel_path = malloc((size_t)u16 + 1);
|
|
|
|
strncpy(rel_path, (char *)buf, (size_t)u16 + 1);
|
2024-07-17 04:30:05 +00:00
|
|
|
} else {
|
2024-07-24 05:52:35 +00:00
|
|
|
rel_path = malloc(u16 + 1);
|
|
|
|
if (fread(rel_path, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
2024-07-17 04:30:05 +00:00
|
|
|
return SDAS_INVALID_FILE;
|
|
|
|
}
|
2024-07-24 05:52:35 +00:00
|
|
|
((char *)rel_path)[u16 - 1] = 0;
|
|
|
|
fprintf(stderr, " Link relative path: %s\n", (char *)rel_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (do_extract) {
|
|
|
|
simple_archiver_helper_make_dirs((const char *)out_f_name);
|
|
|
|
if (abs_path && rel_path) {
|
|
|
|
if (abs_preferred) {
|
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
|
|
|
int ret = symlink(abs_path, out_f_name);
|
|
|
|
if (ret == -1) {
|
|
|
|
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
|
|
|
int ret = symlink(rel_path, out_f_name);
|
|
|
|
if (ret == -1) {
|
|
|
|
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
} else if (abs_path) {
|
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
|
|
|
int ret = symlink(abs_path, out_f_name);
|
|
|
|
if (ret == -1) {
|
|
|
|
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} else if (rel_path) {
|
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
|
|
|
int ret = symlink(rel_path, out_f_name);
|
|
|
|
if (ret == -1) {
|
|
|
|
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
fprintf(
|
|
|
|
stderr,
|
|
|
|
"WARNING: Symlink entry in archive has no paths to link to!\n");
|
|
|
|
}
|
2024-07-17 04:30:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-18 05:39:01 +00:00
|
|
|
return SDAS_SUCCESS;
|
2024-07-17 04:30:05 +00:00
|
|
|
}
|
2024-07-17 05:32:39 +00:00
|
|
|
|
2024-07-17 07:37:32 +00:00
|
|
|
int simple_archiver_de_compress(int pipe_fd_in[2], int pipe_fd_out[2],
|
2024-07-17 10:00:34 +00:00
|
|
|
const char *cmd, void *pid_out) {
|
2024-07-17 06:01:39 +00:00
|
|
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
|
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
2024-07-17 05:32:39 +00:00
|
|
|
posix_spawn_file_actions_t file_actions;
|
|
|
|
memset(&file_actions, 0, sizeof(file_actions));
|
|
|
|
if (posix_spawn_file_actions_init(&file_actions) != 0) {
|
2024-07-17 07:37:32 +00:00
|
|
|
close(pipe_fd_in[0]);
|
|
|
|
close(pipe_fd_out[1]);
|
2024-07-17 05:32:39 +00:00
|
|
|
return 1;
|
2024-07-17 07:37:32 +00:00
|
|
|
} else if (posix_spawn_file_actions_adddup2(&file_actions, pipe_fd_in[0],
|
2024-07-17 06:01:39 +00:00
|
|
|
STDIN_FILENO) != 0) {
|
2024-07-17 05:32:39 +00:00
|
|
|
posix_spawn_file_actions_destroy(&file_actions);
|
2024-07-17 07:37:32 +00:00
|
|
|
close(pipe_fd_in[0]);
|
|
|
|
close(pipe_fd_out[1]);
|
2024-07-17 05:32:39 +00:00
|
|
|
return 2;
|
2024-07-17 07:37:32 +00:00
|
|
|
} else if (posix_spawn_file_actions_adddup2(&file_actions, pipe_fd_out[1],
|
2024-07-17 06:01:39 +00:00
|
|
|
STDOUT_FILENO) != 0) {
|
2024-07-17 05:32:39 +00:00
|
|
|
posix_spawn_file_actions_destroy(&file_actions);
|
2024-07-17 07:37:32 +00:00
|
|
|
close(pipe_fd_in[0]);
|
|
|
|
close(pipe_fd_out[1]);
|
|
|
|
return 3;
|
|
|
|
} else if (posix_spawn_file_actions_addclose(&file_actions, pipe_fd_in[1]) !=
|
|
|
|
0) {
|
|
|
|
posix_spawn_file_actions_destroy(&file_actions);
|
|
|
|
close(pipe_fd_in[0]);
|
|
|
|
close(pipe_fd_out[1]);
|
2024-07-18 13:32:04 +00:00
|
|
|
return 4;
|
2024-07-17 07:37:32 +00:00
|
|
|
} else if (posix_spawn_file_actions_addclose(&file_actions, pipe_fd_out[0]) !=
|
|
|
|
0) {
|
|
|
|
posix_spawn_file_actions_destroy(&file_actions);
|
|
|
|
close(pipe_fd_in[0]);
|
|
|
|
close(pipe_fd_out[1]);
|
2024-07-18 13:32:04 +00:00
|
|
|
return 5;
|
2024-07-17 05:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((cleanup(
|
|
|
|
simple_archiver_helper_cmd_string_argv_free_ptr))) char **cmd_argv =
|
|
|
|
simple_archiver_helper_cmd_string_to_argv(cmd);
|
|
|
|
|
2024-07-17 10:00:34 +00:00
|
|
|
pid_t *pid_t_out = pid_out;
|
|
|
|
if (posix_spawnp(pid_t_out, cmd_argv[0], &file_actions, NULL, cmd_argv,
|
2024-07-17 05:32:39 +00:00
|
|
|
NULL) != 0) {
|
2024-07-17 07:37:32 +00:00
|
|
|
close(pipe_fd_in[0]);
|
|
|
|
close(pipe_fd_out[1]);
|
2024-07-17 05:32:39 +00:00
|
|
|
posix_spawn_file_actions_destroy(&file_actions);
|
2024-07-18 13:32:04 +00:00
|
|
|
return 6;
|
2024-07-17 05:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
posix_spawn_file_actions_destroy(&file_actions);
|
|
|
|
|
|
|
|
return 0;
|
2024-07-17 06:01:39 +00:00
|
|
|
#else
|
|
|
|
return 1;
|
|
|
|
#endif
|
2024-07-17 05:32:39 +00:00
|
|
|
}
|