Compare commits
No commits in common. "main" and "1.2" have entirely different histories.
11 changed files with 111 additions and 607 deletions
|
@ -1,7 +1,7 @@
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
project(SimpleArchiver C)
|
project(SimpleArchiver C)
|
||||||
|
|
||||||
set(SimpleArchiver_VERSION 1.7)
|
set(SimpleArchiver_VERSION 1.0)
|
||||||
|
|
||||||
set(SimpleArchiver_SOURCES
|
set(SimpleArchiver_SOURCES
|
||||||
src/main.c
|
src/main.c
|
||||||
|
|
38
Changelog.md
38
Changelog.md
|
@ -2,44 +2,6 @@
|
||||||
|
|
||||||
## Upcoming Changes
|
## Upcoming Changes
|
||||||
|
|
||||||
## Version 1.7
|
|
||||||
|
|
||||||
Refactor the internal hash-map data structure.
|
|
||||||
|
|
||||||
Minor update to CMakeLists.txt.
|
|
||||||
|
|
||||||
## Version 1.6
|
|
||||||
|
|
||||||
Enforce "safe-links" on extraction by ensuring every extracted symlink actually
|
|
||||||
points to a file in the archive. Additionally any extracted symlinks that don't
|
|
||||||
point to a valid destination is removed. This "enforce safe-links on extract"
|
|
||||||
can be disabled with the "--no-safe-links" option.
|
|
||||||
|
|
||||||
Add "--preserve-symlinks" option that will verbatim store the symlinks' target.
|
|
||||||
Not recommended if symlinks are pointing to absolute paths, which will be
|
|
||||||
clobbered on extraction to a different directory unless if "--no-safe-links" is
|
|
||||||
specified on extraction.
|
|
||||||
|
|
||||||
## Version 1.5
|
|
||||||
|
|
||||||
Previous file-format-v1 implementation of "safe links" still created a symlink
|
|
||||||
if a relative or absolute link existed in the file. This version fixes this, and
|
|
||||||
prevents invalid symlinks from being created. (This check is only done if the
|
|
||||||
bit-flag is set in the file as mentioned in the file-format spec for v1 files.)
|
|
||||||
|
|
||||||
## Version 1.4
|
|
||||||
|
|
||||||
Do "safe links" behavior by default: symlinks pointing to outside of archived
|
|
||||||
files (or invalid symlinks) should not be included in the archive, unless if the
|
|
||||||
option "--no-safe-links" is specified. This is supported in both v0 and v1 file
|
|
||||||
formats.
|
|
||||||
|
|
||||||
## Version 1.3
|
|
||||||
|
|
||||||
Prevent `simplearchiver` from busy-waiting during non-blocking IO by sleeping
|
|
||||||
in "EWOULDBLOCK" conditions. This results in less consumed cpu time by the
|
|
||||||
process, especially during compression.
|
|
||||||
|
|
||||||
## Version 1.2
|
## Version 1.2
|
||||||
|
|
||||||
Proper handling of Ctrl+C (SIGINT). This prevents temporary files from
|
Proper handling of Ctrl+C (SIGINT). This prevents temporary files from
|
||||||
|
|
|
@ -27,8 +27,6 @@ API calls.
|
||||||
--overwrite-create : allows overwriting an archive file
|
--overwrite-create : allows overwriting an archive file
|
||||||
--overwrite-extract : allows overwriting when extracting
|
--overwrite-extract : allows overwriting when extracting
|
||||||
--no-abs-symlink : do not store absolute paths for symlinks
|
--no-abs-symlink : do not store absolute paths for symlinks
|
||||||
--preserve-symlinks : preserve the symlink's path on archive creation instead of deriving abs/relative paths, ignores "--no-abs-symlink" (It is not recommended to use this option, as absolute-path-symlinks may be clobbered on extraction)
|
|
||||||
--no-safe-links : keep symlinks that link to outside archive contents
|
|
||||||
--temp-files-dir <dir> : where to store temporary files created when compressing (defaults to current working directory)
|
--temp-files-dir <dir> : where to store temporary files created when compressing (defaults to current working directory)
|
||||||
--write-version <version> : Force write version file format (default 1)
|
--write-version <version> : Force write version file format (default 1)
|
||||||
--chunk-min-size <bytes> : v1 file format minimum chunk size (default 4194304 or 4MiB)
|
--chunk-min-size <bytes> : v1 file format minimum chunk size (default 4194304 or 4MiB)
|
||||||
|
@ -40,11 +38,6 @@ API calls.
|
||||||
Note that `--compressor` and `--decompressor` cmds must accept data from stdin
|
Note that `--compressor` and `--decompressor` cmds must accept data from stdin
|
||||||
and return processed data to stdout.
|
and return processed data to stdout.
|
||||||
|
|
||||||
## Using the Cosmopolitan-Compiled Version
|
|
||||||
|
|
||||||
Note that on Linux, the `actually_portable_simplearchiver` binaries may attempt
|
|
||||||
to open via Wine (if Wine is installed). [A workaround is mentioned here.](https://github.com/jart/cosmopolitan/blob/master/README.md#linux)
|
|
||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
See the [Changelog](https://git.seodisparate.com/stephenseo/SimpleArchiver/src/branch/main/Changelog.md).
|
See the [Changelog](https://git.seodisparate.com/stephenseo/SimpleArchiver/src/branch/main/Changelog.md).
|
||||||
|
|
|
@ -57,11 +57,6 @@ Following the file-count bytes, the following bytes are added for each file:
|
||||||
2. The second bit is "other execute permission".
|
2. The second bit is "other execute permission".
|
||||||
3. The third bit is UNSET if relative links are preferred, and is SET
|
3. The third bit is UNSET if relative links are preferred, and is SET
|
||||||
if absolute links are preferred.
|
if absolute links are preferred.
|
||||||
4. The fourth bit is set if this file/symlink-entry is invalid and must
|
|
||||||
be skipped. Ignore following bytes after these 4 bytes bit-flags in
|
|
||||||
this specification and skip to the next entry; if marked invalid,
|
|
||||||
the following specification bytes for this file/symlink entry must
|
|
||||||
not exist.
|
|
||||||
3. The third byte.
|
3. The third byte.
|
||||||
1. Currently unused.
|
1. Currently unused.
|
||||||
4. The fourth byte.
|
4. The fourth byte.
|
||||||
|
@ -133,9 +128,6 @@ Following the link-count bytes, the following bytes are added for each symlink:
|
||||||
2. The second byte.
|
2. The second byte.
|
||||||
1. The first bit is "other write permission".
|
1. The first bit is "other write permission".
|
||||||
2. The second bit is "other execute permission".
|
2. The second bit is "other execute permission".
|
||||||
3. If this bit is set, then this entry is marked invalid. The link name
|
|
||||||
will be preserved in this entry, but the following link target paths
|
|
||||||
will be set to zero-length and will not be stored.
|
|
||||||
2. 2 bytes 16-bit unsigned integer "link name" in big-endian. This does not
|
2. 2 bytes 16-bit unsigned integer "link name" in big-endian. This does not
|
||||||
include the NULL at the end of the string. Must not be zero.
|
include the NULL at the end of the string. Must not be zero.
|
||||||
3. X bytes of link-name (length defined by previous value). Is a NULL-terminated
|
3. X bytes of link-name (length defined by previous value). Is a NULL-terminated
|
||||||
|
|
556
src/archiver.c
556
src/archiver.c
|
@ -64,8 +64,6 @@ void handle_sig_int(int sig) {
|
||||||
is_sig_int_occurred = 1;
|
is_sig_int_occurred = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct timespec nonblock_sleep = {.tv_sec = 0, .tv_nsec = 1000000};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct SDArchiverInternalToWrite {
|
typedef struct SDArchiverInternalToWrite {
|
||||||
|
@ -114,20 +112,6 @@ void cleanup_temp_filename_delete(void ***ptrs_array) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_overwrite_filename_delete_simple(char **filename) {
|
|
||||||
if (filename && *filename) {
|
|
||||||
if ((*filename)[0] != 0) {
|
|
||||||
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
|
||||||
unlink(*filename);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
free(*filename);
|
|
||||||
*filename = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_files_fn(void *data, void *ud) {
|
int write_files_fn(void *data, void *ud) {
|
||||||
if (is_sig_int_occurred) {
|
if (is_sig_int_occurred) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -313,7 +297,6 @@ int write_files_fn(void *data, void *ud) {
|
||||||
ret = write(pipe_into_cmd[1], write_buf, write_count);
|
ret = write(pipe_into_cmd[1], write_buf, write_count);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
nanosleep(&nonblock_sleep, NULL);
|
|
||||||
write_again = 1;
|
write_again = 1;
|
||||||
} else {
|
} else {
|
||||||
// Error during write.
|
// Error during write.
|
||||||
|
@ -371,7 +354,7 @@ int write_files_fn(void *data, void *ud) {
|
||||||
// fprintf(stderr, "read_done\n");
|
// fprintf(stderr, "read_done\n");
|
||||||
} else if (ret == -1) {
|
} else if (ret == -1) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
nanosleep(&nonblock_sleep, NULL);
|
// Nop.
|
||||||
} else {
|
} else {
|
||||||
// Read error.
|
// Read error.
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -759,127 +742,48 @@ int write_files_fn(void *data, void *ud) {
|
||||||
// Get absolute path.
|
// Get absolute path.
|
||||||
__attribute__((cleanup(
|
__attribute__((cleanup(
|
||||||
simple_archiver_helper_cleanup_malloced))) void *abs_path = NULL;
|
simple_archiver_helper_cleanup_malloced))) void *abs_path = NULL;
|
||||||
|
#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
|
||||||
__attribute__((cleanup(
|
__attribute__((cleanup(
|
||||||
simple_archiver_helper_cleanup_malloced))) void *rel_path = NULL;
|
simple_archiver_helper_cleanup_malloced))) void *rel_path = NULL;
|
||||||
|
if (abs_path) {
|
||||||
if ((state->parsed->flags & 0x100) != 0) {
|
// Get relative path.
|
||||||
// Preserve symlink target.
|
// First get absolute path of link.
|
||||||
char *path_buf = malloc(1024);
|
__attribute__((cleanup(
|
||||||
ssize_t ret = readlink(file_info->filename, path_buf, 1023);
|
simple_archiver_helper_cleanup_malloced))) void *link_abs_path =
|
||||||
if (ret == -1) {
|
simple_archiver_file_abs_path(file_info->filename);
|
||||||
fprintf(stderr, "WARNING: Failed to get symlink's target!\n");
|
if (!link_abs_path) {
|
||||||
free(path_buf);
|
fprintf(stderr, "WARNING: Failed to get absolute path of link!\n");
|
||||||
((uint8_t *)temp_to_write->buf)[1] |= 0x8;
|
|
||||||
} else {
|
} else {
|
||||||
path_buf[ret] = 0;
|
// fprintf(stderr, "DEBUG: abs_path: %s\nDEBUG: link_abs_path: %s\n",
|
||||||
if (path_buf[0] == '/') {
|
// (char*)abs_path, (char*)link_abs_path);
|
||||||
abs_path = path_buf;
|
|
||||||
((uint8_t *)temp_to_write->buf)[1] |= 0x4;
|
|
||||||
} else {
|
|
||||||
rel_path = path_buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
abs_path = realpath(file_info->filename, NULL);
|
|
||||||
if (abs_path) {
|
|
||||||
// Get relative path.
|
|
||||||
// First get absolute path of link.
|
|
||||||
__attribute__((cleanup(
|
|
||||||
simple_archiver_helper_cleanup_malloced))) void *link_abs_path =
|
|
||||||
simple_archiver_file_abs_path(file_info->filename);
|
|
||||||
if (!link_abs_path) {
|
|
||||||
fprintf(stderr, "WARNING: Failed to get absolute path of link!\n");
|
|
||||||
} else {
|
|
||||||
// fprintf(stderr, "DEBUG: abs_path: %s\nDEBUG: link_abs_path: %s\n",
|
|
||||||
// (char*)abs_path, (char*)link_abs_path);
|
|
||||||
|
|
||||||
rel_path = simple_archiver_filenames_to_relative_path(link_abs_path,
|
rel_path =
|
||||||
abs_path);
|
simple_archiver_filenames_to_relative_path(link_abs_path, abs_path);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if absolute path refers to one of the filenames.
|
// Check if absolute path refers to one of the filenames.
|
||||||
if (abs_path && (state->parsed->flags & 0x20) == 0 &&
|
if (abs_path && (state->parsed->flags & 0x20) == 0 &&
|
||||||
(state->parsed->flags & 0x100) == 0 &&
|
|
||||||
!simple_archiver_hash_map_get(state->map, abs_path,
|
!simple_archiver_hash_map_get(state->map, abs_path,
|
||||||
strlen(abs_path) + 1)) {
|
strlen(abs_path) + 1)) {
|
||||||
// Is not a filename being archived.
|
// Is not a filename being archived, set preference to absolute path.
|
||||||
if ((state->parsed->flags & 0x80) != 0) {
|
|
||||||
// No safe links, 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");
|
|
||||||
((uint8_t *)temp_to_write->buf)[1] |= 0x4;
|
|
||||||
} else {
|
|
||||||
// Safe links, do not store symlink!
|
|
||||||
fprintf(stderr,
|
|
||||||
"WARNING: Symlink \"%s\" points to outside archive contents, "
|
|
||||||
"will not be stored! (Use \"--no-safe-links\" to disable this "
|
|
||||||
"behavior)\n",
|
|
||||||
file_info->filename);
|
|
||||||
((uint8_t *)temp_to_write->buf)[1] |= 0x8;
|
|
||||||
}
|
|
||||||
} else if ((state->parsed->flags & 0x100) != 0 &&
|
|
||||||
(state->parsed->flags & 0x80) == 0 &&
|
|
||||||
(((uint8_t *)temp_to_write->buf)[1] & 0x8) == 0) {
|
|
||||||
__attribute__((cleanup(
|
|
||||||
simple_archiver_helper_cleanup_c_string))) char *resolved_path = NULL;
|
|
||||||
if (abs_path || rel_path) {
|
|
||||||
resolved_path = realpath(file_info->filename, NULL);
|
|
||||||
if (!resolved_path) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"WARNING: Symlink \"%s\" is invalid, will not be stored! "
|
|
||||||
"(Use \"--no-safe-links\" to disable this behavior)\n",
|
|
||||||
file_info->filename);
|
|
||||||
((uint8_t *)temp_to_write->buf)[1] |= 0x8;
|
|
||||||
} else if (!simple_archiver_hash_map_get(state->map, resolved_path,
|
|
||||||
strlen(resolved_path) + 1)) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"WARNING: Symlink \"%s\" points to outside archive contents, "
|
|
||||||
"will not be stored! (Use \"--no-safe-links\" to disable "
|
|
||||||
"this behavior)\n",
|
|
||||||
file_info->filename);
|
|
||||||
((uint8_t *)temp_to_write->buf)[1] |= 0x8;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr,
|
|
||||||
"WARNING: Unable to get target path from symlink \"%s\"!\n",
|
|
||||||
file_info->filename);
|
|
||||||
((uint8_t *)temp_to_write->buf)[1] |= 0x8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!abs_path && !rel_path) {
|
|
||||||
// No valid paths, set as invalid.
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"WARNING: Could not get valid abs/rel path for symlink \"%s\" "
|
"NOTICE: abs_path exists, \"--no-abs-symlink\" not specified, "
|
||||||
"(invalid symlink)!\n",
|
"and link refers to file NOT in archive; preferring abs_path.\n");
|
||||||
file_info->filename);
|
((uint8_t *)temp_to_write->buf)[1] |= 0x4;
|
||||||
((uint8_t *)temp_to_write->buf)[1] |= 0x8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the 4 byte bit-flags for file.
|
// Store the 4 byte bit-flags for file.
|
||||||
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
|
||||||
|
|
||||||
if ((((uint8_t *)temp_to_write->buf)[1] & 0x8) != 0) {
|
|
||||||
// Skipped symlink.
|
|
||||||
simple_archiver_list_get(to_write, write_list_datas_fn, state->out_f);
|
|
||||||
simple_archiver_list_free(&to_write);
|
|
||||||
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);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the absolute and relative paths.
|
// Store the absolute and relative paths.
|
||||||
if (!abs_path) {
|
if (!abs_path) {
|
||||||
if ((state->parsed->flags & 0x100) == 0) {
|
fprintf(stderr,
|
||||||
fprintf(stderr,
|
"WARNING: Failed to get absolute path of link destination!\n");
|
||||||
"WARNING: Failed to get absolute path of link destination!\n");
|
|
||||||
}
|
|
||||||
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
temp_to_write = malloc(sizeof(SDArchiverInternalToWrite));
|
||||||
temp_to_write->buf = malloc(2);
|
temp_to_write->buf = malloc(2);
|
||||||
temp_to_write->size = 2;
|
temp_to_write->size = 2;
|
||||||
|
@ -952,17 +856,9 @@ int write_files_fn(void *data, void *ud) {
|
||||||
// Write all previously set data.
|
// Write all previously set data.
|
||||||
fprintf(stderr, "Writing symlink info: %s\n", file_info->filename);
|
fprintf(stderr, "Writing symlink info: %s\n", file_info->filename);
|
||||||
if ((state->parsed->flags & 0x20) == 0) {
|
if ((state->parsed->flags & 0x20) == 0) {
|
||||||
if (abs_path) {
|
fprintf(stderr, " abs path: %s\n", (char *)abs_path);
|
||||||
fprintf(stderr, " abs path: %s\n", (char *)abs_path);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, " abs path is NOT set\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rel_path) {
|
|
||||||
fprintf(stderr, " rel path: %s\n", (char *)rel_path);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, " rel path is NOT set\n");
|
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, " rel path: %s\n", (char *)rel_path);
|
||||||
simple_archiver_list_get(to_write, write_list_datas_fn, state->out_f);
|
simple_archiver_list_get(to_write, write_list_datas_fn, state->out_f);
|
||||||
simple_archiver_list_free(&to_write);
|
simple_archiver_list_free(&to_write);
|
||||||
}
|
}
|
||||||
|
@ -1038,15 +934,10 @@ int filenames_to_abs_map_fn(void *data, void *ud) {
|
||||||
char *fullpath_dirname_copy = malloc(strlen(fullpath_dirname) + 1);
|
char *fullpath_dirname_copy = malloc(strlen(fullpath_dirname) + 1);
|
||||||
strncpy(fullpath_dirname_copy, fullpath_dirname,
|
strncpy(fullpath_dirname_copy, fullpath_dirname,
|
||||||
strlen(fullpath_dirname) + 1);
|
strlen(fullpath_dirname) + 1);
|
||||||
if (!simple_archiver_hash_map_get(abs_filenames, fullpath_dirname_copy,
|
simple_archiver_hash_map_insert(
|
||||||
strlen(fullpath_dirname_copy) + 1)) {
|
abs_filenames, fullpath_dirname_copy, fullpath_dirname_copy,
|
||||||
simple_archiver_hash_map_insert(
|
strlen(fullpath_dirname_copy) + 1,
|
||||||
abs_filenames, fullpath_dirname_copy, fullpath_dirname_copy,
|
simple_archiver_helper_datastructure_cleanup_nop, NULL);
|
||||||
strlen(fullpath_dirname_copy) + 1,
|
|
||||||
simple_archiver_helper_datastructure_cleanup_nop, NULL);
|
|
||||||
} else {
|
|
||||||
free(fullpath_dirname_copy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
prev = fullpath_dirname;
|
prev = fullpath_dirname;
|
||||||
}
|
}
|
||||||
|
@ -1280,7 +1171,6 @@ int read_decomp_to_out_file(const char *out_filename, int in_pipe,
|
||||||
} else {
|
} else {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
// Non-blocking read from pipe.
|
// Non-blocking read from pipe.
|
||||||
nanosleep(&nonblock_sleep, NULL);
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
// Error.
|
// Error.
|
||||||
|
@ -1320,7 +1210,6 @@ int read_decomp_to_out_file(const char *out_filename, int in_pipe,
|
||||||
} else {
|
} else {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
// Non-blocking read from pipe.
|
// Non-blocking read from pipe.
|
||||||
nanosleep(&nonblock_sleep, NULL);
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
// Error.
|
// Error.
|
||||||
|
@ -1749,29 +1638,6 @@ int files_to_chunk_count(void *data, void *ud) {
|
||||||
|
|
||||||
int greater_fn(int64_t a, int64_t b) { return a > b; }
|
int greater_fn(int64_t a, int64_t b) { return a > b; }
|
||||||
|
|
||||||
void simple_archiver_internal_paths_to_files_map(SDArchiverHashMap *files_map,
|
|
||||||
const char *filename) {
|
|
||||||
simple_archiver_hash_map_insert(
|
|
||||||
files_map, (void *)1, strdup((const char *)filename),
|
|
||||||
strlen((const char *)filename) + 1,
|
|
||||||
simple_archiver_helper_datastructure_cleanup_nop, NULL);
|
|
||||||
__attribute__((
|
|
||||||
cleanup(simple_archiver_helper_cleanup_c_string))) char *filename_copy =
|
|
||||||
strdup(filename);
|
|
||||||
char *filename_dirname = dirname(filename_copy);
|
|
||||||
|
|
||||||
while (strcmp(filename_dirname, ".") != 0) {
|
|
||||||
if (!simple_archiver_hash_map_get(files_map, filename_dirname,
|
|
||||||
strlen(filename_dirname) + 1)) {
|
|
||||||
simple_archiver_hash_map_insert(
|
|
||||||
files_map, (void *)1, strdup(filename_dirname),
|
|
||||||
strlen(filename_dirname) + 1,
|
|
||||||
simple_archiver_helper_datastructure_cleanup_nop, NULL);
|
|
||||||
}
|
|
||||||
filename_dirname = dirname(filename_dirname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *simple_archiver_error_to_string(enum SDArchiverStateReturns error) {
|
char *simple_archiver_error_to_string(enum SDArchiverStateReturns error) {
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case SDAS_SUCCESS:
|
case SDAS_SUCCESS:
|
||||||
|
@ -2151,96 +2017,31 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
|
||||||
node = node->next;
|
node = node->next;
|
||||||
++u32;
|
++u32;
|
||||||
memset(buf, 0, 2);
|
memset(buf, 0, 2);
|
||||||
|
|
||||||
uint_fast8_t is_invalid = 0;
|
|
||||||
|
|
||||||
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
__attribute__((cleanup(
|
// Check if symlink points to thing to be stored into archive.
|
||||||
simple_archiver_helper_cleanup_malloced))) void *abs_path = NULL;
|
__attribute__((
|
||||||
|
cleanup(simple_archiver_helper_cleanup_malloced))) void *abs_path =
|
||||||
|
realpath(node->data, NULL);
|
||||||
__attribute__((cleanup(
|
__attribute__((cleanup(
|
||||||
simple_archiver_helper_cleanup_malloced))) void *rel_path = NULL;
|
simple_archiver_helper_cleanup_malloced))) void *rel_path = NULL;
|
||||||
if ((state->parsed->flags & 0x100) != 0) {
|
if (abs_path) {
|
||||||
// Preserve symlink target.
|
__attribute__((cleanup(
|
||||||
char *path_buf = malloc(1024);
|
simple_archiver_helper_cleanup_malloced))) void *link_abs_path =
|
||||||
ssize_t ret = readlink(node->data, path_buf, 1023);
|
simple_archiver_file_abs_path(node->data);
|
||||||
if (ret == -1) {
|
if (!link_abs_path) {
|
||||||
fprintf(stderr, "WARNING: Failed to get symlink's target!\n");
|
fprintf(stderr, "WARNING: Failed to get absolute path to link!\n");
|
||||||
free(path_buf);
|
|
||||||
is_invalid = 1;
|
|
||||||
} else {
|
} else {
|
||||||
path_buf[ret] = 0;
|
rel_path = simple_archiver_filenames_to_relative_path(link_abs_path,
|
||||||
if (path_buf[0] == '/') {
|
abs_path);
|
||||||
abs_path = path_buf;
|
|
||||||
buf[0] |= 1;
|
|
||||||
} else {
|
|
||||||
rel_path = path_buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
abs_path = realpath(node->data, NULL);
|
|
||||||
// Check if symlink points to thing to be stored into archive.
|
|
||||||
if (abs_path) {
|
|
||||||
__attribute__((cleanup(
|
|
||||||
simple_archiver_helper_cleanup_malloced))) void *link_abs_path =
|
|
||||||
simple_archiver_file_abs_path(node->data);
|
|
||||||
if (!link_abs_path) {
|
|
||||||
fprintf(stderr, "WARNING: Failed to get absolute path to link!\n");
|
|
||||||
} else {
|
|
||||||
rel_path = simple_archiver_filenames_to_relative_path(link_abs_path,
|
|
||||||
abs_path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abs_path && (state->parsed->flags & 0x20) == 0 &&
|
if (abs_path && (state->parsed->flags & 0x20) == 0 &&
|
||||||
(state->parsed->flags & 0x100) == 0 &&
|
|
||||||
!simple_archiver_hash_map_get(abs_filenames, abs_path,
|
!simple_archiver_hash_map_get(abs_filenames, abs_path,
|
||||||
strlen(abs_path) + 1)) {
|
strlen(abs_path) + 1)) {
|
||||||
// Is not a filename being archived.
|
// Is not a filename being archived, set preference to absolute path.
|
||||||
if ((state->parsed->flags & 0x80) == 0) {
|
buf[0] |= 1;
|
||||||
// Not a "safe link", mark invalid and continue.
|
|
||||||
is_invalid = 1;
|
|
||||||
fprintf(stderr,
|
|
||||||
"WARNING: \"%s\" points to outside of archived files (or is "
|
|
||||||
"invalid) and \"--no-safe-links\" not specified, will not "
|
|
||||||
"store abs/rel-links to this entry!\n",
|
|
||||||
(const char *)node->data);
|
|
||||||
} else {
|
|
||||||
// Safe links disabled, set preference to absolute path.
|
|
||||||
buf[0] |= 1;
|
|
||||||
}
|
|
||||||
} else if ((state->parsed->flags & 0x100) != 0 &&
|
|
||||||
(state->parsed->flags & 0x80) == 0 && !is_invalid) {
|
|
||||||
__attribute__((cleanup(
|
|
||||||
simple_archiver_helper_cleanup_c_string))) char *target_realpath =
|
|
||||||
realpath(node->data, NULL);
|
|
||||||
if (!target_realpath) {
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"WARNING: \"%s\" is an invalid symlink and \"--no-safe-links\" "
|
|
||||||
"not specified, will skip this symlink!\n",
|
|
||||||
(const char *)node->data);
|
|
||||||
is_invalid = 1;
|
|
||||||
} else if (!simple_archiver_hash_map_get(abs_filenames, target_realpath,
|
|
||||||
strlen(target_realpath) + 1)) {
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"WARNING: \"%s\" points to outside of archived files and "
|
|
||||||
"\"--no-safe-links\" not specified, will skip this symlink!\n",
|
|
||||||
(const char *)node->data);
|
|
||||||
is_invalid = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!abs_path && !rel_path) {
|
|
||||||
// No valid paths, mark as invalid.
|
|
||||||
fprintf(stderr,
|
|
||||||
"WARNING: \"%s\" is an invalid symlink, will not store rel/abs "
|
|
||||||
"link paths!\n",
|
|
||||||
(const char *)node->data);
|
|
||||||
is_invalid = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get symlink stats for permissions.
|
// Get symlink stats for permissions.
|
||||||
|
@ -2283,11 +2084,6 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
|
||||||
buf[0] = 0xFE;
|
buf[0] = 0xFE;
|
||||||
buf[1] = 3;
|
buf[1] = 3;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (is_invalid) {
|
|
||||||
buf[1] |= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fwrite(buf, 1, 2, out_f) != 2) {
|
if (fwrite(buf, 1, 2, out_f) != 2) {
|
||||||
return SDAS_FAILED_TO_WRITE;
|
return SDAS_FAILED_TO_WRITE;
|
||||||
}
|
}
|
||||||
|
@ -2308,7 +2104,7 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
|
||||||
return SDAS_FAILED_TO_WRITE;
|
return SDAS_FAILED_TO_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abs_path && (state->parsed->flags & 0x20) == 0 && !is_invalid) {
|
if (abs_path && (state->parsed->flags & 0x20) == 0) {
|
||||||
len = strlen(abs_path);
|
len = strlen(abs_path);
|
||||||
if (len >= 0xFFFF) {
|
if (len >= 0xFFFF) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -2332,7 +2128,7 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rel_path && !is_invalid) {
|
if (rel_path) {
|
||||||
len = strlen(rel_path);
|
len = strlen(rel_path);
|
||||||
if (len >= 0xFFFF) {
|
if (len >= 0xFFFF) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -2640,7 +2436,6 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
|
||||||
// Non-blocking write.
|
// Non-blocking write.
|
||||||
has_hold = (int)fread_ret;
|
has_hold = (int)fread_ret;
|
||||||
memcpy(hold_buf, buf, fread_ret);
|
memcpy(hold_buf, buf, fread_ret);
|
||||||
nanosleep(&nonblock_sleep, NULL);
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
|
@ -2667,7 +2462,6 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
|
||||||
if (write_ret < 0) {
|
if (write_ret < 0) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
// Non-blocking write.
|
// Non-blocking write.
|
||||||
nanosleep(&nonblock_sleep, NULL);
|
|
||||||
} else {
|
} else {
|
||||||
return SDAS_INTERNAL_ERROR;
|
return SDAS_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -2690,7 +2484,6 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
|
||||||
if (read_ret < 0) {
|
if (read_ret < 0) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
// Non-blocking read.
|
// Non-blocking read.
|
||||||
nanosleep(&nonblock_sleep, NULL);
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"ERROR: Reading from compressor, pipe read error!\n");
|
"ERROR: Reading from compressor, pipe read error!\n");
|
||||||
|
@ -2725,7 +2518,6 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
|
||||||
if (read_ret < 0) {
|
if (read_ret < 0) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
// Non-blocking read.
|
// Non-blocking read.
|
||||||
nanosleep(&nonblock_sleep, NULL);
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"ERROR: Reading from compressor, pipe read error!\n");
|
"ERROR: Reading from compressor, pipe read error!\n");
|
||||||
|
@ -2985,18 +2777,6 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
// fprintf(stderr, "\"%s\" put in map\n", key);
|
// fprintf(stderr, "\"%s\" put in map\n", key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((cleanup(simple_archiver_list_free)))
|
|
||||||
SDArchiverLinkedList *links_list =
|
|
||||||
state && state->parsed && state->parsed->flags & 0x80
|
|
||||||
? NULL
|
|
||||||
: simple_archiver_list_init();
|
|
||||||
__attribute__((cleanup(simple_archiver_hash_map_free)))
|
|
||||||
SDArchiverHashMap *files_map =
|
|
||||||
state && state->parsed && state->parsed->flags & 0x80
|
|
||||||
? NULL
|
|
||||||
: simple_archiver_hash_map_init();
|
|
||||||
|
|
||||||
for (uint32_t idx = 0; idx < size; ++idx) {
|
for (uint32_t idx = 0; idx < size; ++idx) {
|
||||||
if (is_sig_int_occurred) {
|
if (is_sig_int_occurred) {
|
||||||
return SDAS_SIGINT;
|
return SDAS_SIGINT;
|
||||||
|
@ -3013,9 +2793,6 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
simple_archiver_helper_cleanup_malloced))) void *out_f_name = NULL;
|
simple_archiver_helper_cleanup_malloced))) void *out_f_name = NULL;
|
||||||
__attribute__((cleanup(simple_archiver_helper_cleanup_FILE))) FILE *out_f =
|
__attribute__((cleanup(simple_archiver_helper_cleanup_FILE))) FILE *out_f =
|
||||||
NULL;
|
NULL;
|
||||||
__attribute__((cleanup(
|
|
||||||
cleanup_overwrite_filename_delete_simple))) char *to_overwrite_dest =
|
|
||||||
NULL;
|
|
||||||
if (u16 < SIMPLE_ARCHIVER_BUFFER_SIZE) {
|
if (u16 < SIMPLE_ARCHIVER_BUFFER_SIZE) {
|
||||||
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;
|
||||||
|
@ -3045,14 +2822,12 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
if (errno == ELOOP) {
|
if (errno == ELOOP) {
|
||||||
// Is an existing symbolic file.
|
// Is an existing symbolic file.
|
||||||
// Defer deletion to after "is invalid" check.
|
unlink((const char *)buf);
|
||||||
to_overwrite_dest = strdup((const char *)buf);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
close(fd);
|
close(fd);
|
||||||
// Is an existing file.
|
// Is an existing file.
|
||||||
// Defer deletion to after "is invalid" check.
|
unlink((const char *)buf);
|
||||||
to_overwrite_dest = strdup((const char *)buf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!skip) {
|
if (!skip) {
|
||||||
|
@ -3094,14 +2869,12 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
if (errno == ELOOP) {
|
if (errno == ELOOP) {
|
||||||
// Is an existing symbolic file.
|
// Is an existing symbolic file.
|
||||||
// Defer deletion to after "is invalid" check.
|
unlink((const char *)uc_heap_buf);
|
||||||
to_overwrite_dest = strdup((const char *)uc_heap_buf);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
close(fd);
|
close(fd);
|
||||||
// Is an existing file.
|
// Is an existing file.
|
||||||
// Defer deletion to after "is invalid" check.
|
unlink((const char *)uc_heap_buf);
|
||||||
to_overwrite_dest = strdup((const char *)uc_heap_buf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!skip) {
|
if (!skip) {
|
||||||
|
@ -3116,21 +2889,6 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
return SDAS_INVALID_FILE;
|
return SDAS_INVALID_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for "invalid entry" flag.
|
|
||||||
if ((buf[1] & 0x8) != 0) {
|
|
||||||
free(to_overwrite_dest);
|
|
||||||
to_overwrite_dest = NULL;
|
|
||||||
fprintf(stderr, " This file entry was marked invalid, skipping...\n");
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
// Do deferred overwrite action: remove existing file/symlink.
|
|
||||||
cleanup_overwrite_filename_delete_simple(&to_overwrite_dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (files_map && !skip && out_f_name) {
|
|
||||||
simple_archiver_internal_paths_to_files_map(files_map, out_f_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
|
@ -3396,7 +3154,6 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
}
|
}
|
||||||
} else if (write_ret == -1) {
|
} else if (write_ret == -1) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
nanosleep(&nonblock_sleep, NULL);
|
|
||||||
write_again = 1;
|
write_again = 1;
|
||||||
} else {
|
} else {
|
||||||
// Error.
|
// Error.
|
||||||
|
@ -3440,7 +3197,6 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
} else if (read_ret == -1) {
|
} else if (read_ret == -1) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
// No bytes to read yet.
|
// No bytes to read yet.
|
||||||
nanosleep(&nonblock_sleep, NULL);
|
|
||||||
} else {
|
} else {
|
||||||
// Error.
|
// Error.
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -3609,19 +3365,19 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (retry_symlink) {
|
if (retry_symlink) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" WARNING: Failed to create symlink after removing "
|
"WARNING: Failed to create symlink after removing "
|
||||||
"existing symlink!\n");
|
"existing symlink!\n");
|
||||||
goto V0_SYMLINK_CREATE_AFTER_0;
|
goto V0_SYMLINK_CREATE_AFTER_0;
|
||||||
} else if (errno == EEXIST) {
|
} else if (errno == EEXIST) {
|
||||||
if ((state->parsed->flags & 8) == 0) {
|
if ((state->parsed->flags & 8) == 0) {
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
" WARNING: Symlink already exists and "
|
"WARNING: Symlink already exists and "
|
||||||
"\"--overwrite-extract\" is not specified, skipping!\n");
|
"\"--overwrite-extract\" is not specified, skipping!\n");
|
||||||
goto V0_SYMLINK_CREATE_AFTER_0;
|
goto V0_SYMLINK_CREATE_AFTER_0;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" NOTICE: Symlink already exists and "
|
"NOTICE: Symlink already exists and "
|
||||||
"\"--overwrite-extract\" specified, attempting to "
|
"\"--overwrite-extract\" specified, attempting to "
|
||||||
"overwrite...\n");
|
"overwrite...\n");
|
||||||
unlink(out_f_name);
|
unlink(out_f_name);
|
||||||
|
@ -3632,21 +3388,17 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (links_list) {
|
|
||||||
simple_archiver_list_add(links_list, strdup(out_f_name), NULL);
|
|
||||||
}
|
|
||||||
ret = fchmodat(AT_FDCWD, out_f_name, permissions,
|
ret = fchmodat(AT_FDCWD, out_f_name, permissions,
|
||||||
AT_SYMLINK_NOFOLLOW);
|
AT_SYMLINK_NOFOLLOW);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (errno == EOPNOTSUPP) {
|
if (errno == EOPNOTSUPP) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" NOTICE: Setting permissions of symlink is not "
|
"NOTICE: Setting permissions of symlink is not "
|
||||||
"supported by FS/OS!\n");
|
"supported by FS/OS!\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr,
|
"WARNING: Failed to set permissions of symlink (%d)!\n",
|
||||||
" WARNING: Failed to set permissions of symlink (%d)!\n",
|
errno);
|
||||||
errno);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
V0_SYMLINK_CREATE_AFTER_0:
|
V0_SYMLINK_CREATE_AFTER_0:
|
||||||
|
@ -3663,19 +3415,19 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (retry_symlink) {
|
if (retry_symlink) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" WARNING: Failed to create symlink after removing "
|
"WARNING: Failed to create symlink after removing "
|
||||||
"existing symlink!\n");
|
"existing symlink!\n");
|
||||||
goto V0_SYMLINK_CREATE_AFTER_1;
|
goto V0_SYMLINK_CREATE_AFTER_1;
|
||||||
} else if (errno == EEXIST) {
|
} else if (errno == EEXIST) {
|
||||||
if ((state->parsed->flags & 8) == 0) {
|
if ((state->parsed->flags & 8) == 0) {
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
" WARNING: Symlink already exists and "
|
"WARNING: Symlink already exists and "
|
||||||
"\"--overwrite-extract\" is not specified, skipping!\n");
|
"\"--overwrite-extract\" is not specified, skipping!\n");
|
||||||
goto V0_SYMLINK_CREATE_AFTER_1;
|
goto V0_SYMLINK_CREATE_AFTER_1;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" NOTICE: Symlink already exists and "
|
"NOTICE: Symlink already exists and "
|
||||||
"\"--overwrite-extract\" specified, attempting to "
|
"\"--overwrite-extract\" specified, attempting to "
|
||||||
"overwrite...\n");
|
"overwrite...\n");
|
||||||
unlink(out_f_name);
|
unlink(out_f_name);
|
||||||
|
@ -3686,21 +3438,17 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (links_list) {
|
|
||||||
simple_archiver_list_add(links_list, strdup(out_f_name), NULL);
|
|
||||||
}
|
|
||||||
ret = fchmodat(AT_FDCWD, out_f_name, permissions,
|
ret = fchmodat(AT_FDCWD, out_f_name, permissions,
|
||||||
AT_SYMLINK_NOFOLLOW);
|
AT_SYMLINK_NOFOLLOW);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (errno == EOPNOTSUPP) {
|
if (errno == EOPNOTSUPP) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" NOTICE: Setting permissions of symlink is not "
|
"NOTICE: Setting permissions of symlink is not "
|
||||||
"supported by FS/OS!\n");
|
"supported by FS/OS!\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr,
|
"WARNING: Failed to set permissions of symlink (%d)!\n",
|
||||||
" WARNING: Failed to set permissions of symlink (%d)!\n",
|
errno);
|
||||||
errno);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
V0_SYMLINK_CREATE_AFTER_1:
|
V0_SYMLINK_CREATE_AFTER_1:
|
||||||
|
@ -3715,20 +3463,16 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
||||||
}
|
}
|
||||||
if (links_list) {
|
|
||||||
simple_archiver_list_add(links_list, strdup(out_f_name), NULL);
|
|
||||||
}
|
|
||||||
ret =
|
ret =
|
||||||
fchmodat(AT_FDCWD, out_f_name, permissions, AT_SYMLINK_NOFOLLOW);
|
fchmodat(AT_FDCWD, out_f_name, permissions, AT_SYMLINK_NOFOLLOW);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (errno == EOPNOTSUPP) {
|
if (errno == EOPNOTSUPP) {
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr,
|
"NOTICE: Setting permissions of symlink is not supported "
|
||||||
" NOTICE: Setting permissions of symlink is not supported "
|
"by FS/OS!\n");
|
||||||
"by FS/OS!\n");
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" WARNING: Failed to set permissions of symlink (%d)!\n",
|
"WARNING: Failed to set permissions of symlink (%d)!\n",
|
||||||
errno);
|
errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3741,20 +3485,16 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
||||||
}
|
}
|
||||||
if (links_list) {
|
|
||||||
simple_archiver_list_add(links_list, strdup(out_f_name), NULL);
|
|
||||||
}
|
|
||||||
ret =
|
ret =
|
||||||
fchmodat(AT_FDCWD, out_f_name, permissions, AT_SYMLINK_NOFOLLOW);
|
fchmodat(AT_FDCWD, out_f_name, permissions, AT_SYMLINK_NOFOLLOW);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (errno == EOPNOTSUPP) {
|
if (errno == EOPNOTSUPP) {
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr,
|
"NOTICE: Setting permissions of symlink is not supported "
|
||||||
" NOTICE: Setting permissions of symlink is not supported "
|
"by FS/OS!\n");
|
||||||
"by FS/OS!\n");
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" WARNING: Failed to set permissions of symlink (%d)!\n",
|
"WARNING: Failed to set permissions of symlink (%d)!\n",
|
||||||
errno);
|
errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3762,16 +3502,12 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
||||||
} else {
|
} else {
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
" WARNING: Symlink entry in archive has no paths to link to!\n");
|
"WARNING: Symlink entry in archive has no paths to link to!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_extract && links_list && files_map) {
|
|
||||||
simple_archiver_safe_links_enforce(links_list, files_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_sig_int_occurred) {
|
if (is_sig_int_occurred) {
|
||||||
return SDAS_SIGINT;
|
return SDAS_SIGINT;
|
||||||
}
|
}
|
||||||
|
@ -3816,21 +3552,6 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((cleanup(simple_archiver_list_free)))
|
|
||||||
SDArchiverLinkedList *links_list =
|
|
||||||
state && state->parsed && state->parsed->flags & 0x80
|
|
||||||
? NULL
|
|
||||||
: simple_archiver_list_init();
|
|
||||||
__attribute__((cleanup(simple_archiver_hash_map_free)))
|
|
||||||
SDArchiverHashMap *files_map =
|
|
||||||
state && state->parsed && state->parsed->flags & 0x80
|
|
||||||
? NULL
|
|
||||||
: simple_archiver_hash_map_init();
|
|
||||||
|
|
||||||
__attribute__((
|
|
||||||
cleanup(simple_archiver_helper_cleanup_c_string))) char *cwd_realpath =
|
|
||||||
realpath(".", NULL);
|
|
||||||
|
|
||||||
const int_fast8_t is_compressed = (buf[0] & 1) ? 1 : 0;
|
const int_fast8_t is_compressed = (buf[0] & 1) ? 1 : 0;
|
||||||
|
|
||||||
__attribute__((cleanup(
|
__attribute__((cleanup(
|
||||||
|
@ -3895,11 +3616,6 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
return SDAS_INVALID_FILE;
|
return SDAS_INVALID_FILE;
|
||||||
}
|
}
|
||||||
const uint_fast8_t absolute_preferred = (buf[0] & 1) ? 1 : 0;
|
const uint_fast8_t absolute_preferred = (buf[0] & 1) ? 1 : 0;
|
||||||
const uint_fast8_t is_invalid = (buf[1] & 4) ? 1 : 0;
|
|
||||||
|
|
||||||
if (is_invalid) {
|
|
||||||
fprintf(stderr, " WARNING: This symlink entry was marked invalid!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
@ -3909,7 +3625,7 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
|
|
||||||
uint_fast8_t link_extracted = 0;
|
uint_fast8_t link_extracted = 0;
|
||||||
uint_fast8_t skip_due_to_map = 0;
|
uint_fast8_t skip_due_to_map = 0;
|
||||||
uint_fast8_t skip_due_to_invalid = is_invalid ? 1 : 0;
|
uint_fast8_t skip_due_to_invalid = 0;
|
||||||
|
|
||||||
if (fread(buf, 1, 2, in_f) != 2) {
|
if (fread(buf, 1, 2, in_f) != 2) {
|
||||||
return SDAS_INVALID_FILE;
|
return SDAS_INVALID_FILE;
|
||||||
|
@ -3981,22 +3697,21 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
ret = symlink(path, link_name);
|
ret = symlink(path, link_name);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (link_create_retry) {
|
if (link_create_retry) {
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr,
|
"WARNING: Failed to create symlink after removing existing "
|
||||||
" WARNING: Failed to create symlink after removing existing "
|
"symlink!\n");
|
||||||
"symlink!\n");
|
|
||||||
goto V1_SYMLINK_CREATE_AFTER_0;
|
goto V1_SYMLINK_CREATE_AFTER_0;
|
||||||
} else if (errno == EEXIST) {
|
} else if (errno == EEXIST) {
|
||||||
if ((state->parsed->flags & 8) == 0) {
|
if ((state->parsed->flags & 8) == 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" WARNING: Symlink already exists and "
|
"WARNING: Symlink already exists and "
|
||||||
"\"--overwrite-extract\" is not specified, skipping!\n");
|
"\"--overwrite-extract\" is not specified, skipping!\n");
|
||||||
goto V1_SYMLINK_CREATE_AFTER_0;
|
goto V1_SYMLINK_CREATE_AFTER_0;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(
|
||||||
" NOTICE: Symlink already exists and "
|
stderr,
|
||||||
"\"--overwrite-extract\" specified, attempting to "
|
"NOTICE: Symlink already exists and \"--overwrite-extract\" "
|
||||||
"overwrite...\n");
|
"specified, attempting to overwrite...\n");
|
||||||
unlink(link_name);
|
unlink(link_name);
|
||||||
link_create_retry = 1;
|
link_create_retry = 1;
|
||||||
goto V1_SYMLINK_CREATE_RETRY_0;
|
goto V1_SYMLINK_CREATE_RETRY_0;
|
||||||
|
@ -4008,11 +3723,11 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (errno == EOPNOTSUPP) {
|
if (errno == EOPNOTSUPP) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" NOTICE: Setting permissions of symlink is not supported "
|
"NOTICE: Setting permissions of symlink is not supported "
|
||||||
"by FS/OS!\n");
|
"by FS/OS!\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" WARNING: Failed to set permissions of symlink (%d)!\n",
|
"WARNING: Failed to set permissions of symlink (%d)!\n",
|
||||||
errno);
|
errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4021,7 +3736,7 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
V1_SYMLINK_CREATE_AFTER_0:
|
V1_SYMLINK_CREATE_AFTER_0:
|
||||||
link_create_retry = 1;
|
link_create_retry = 1;
|
||||||
#endif
|
#endif
|
||||||
} else if (!do_extract) {
|
} else {
|
||||||
fprintf(stderr, " Abs path: %s\n", path);
|
fprintf(stderr, " Abs path: %s\n", path);
|
||||||
}
|
}
|
||||||
} else if (!do_extract) {
|
} else if (!do_extract) {
|
||||||
|
@ -4054,22 +3769,21 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
ret = symlink(path, link_name);
|
ret = symlink(path, link_name);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (link_create_retry) {
|
if (link_create_retry) {
|
||||||
fprintf(
|
fprintf(stderr,
|
||||||
stderr,
|
"WARNING: Failed to create symlink after removing existing "
|
||||||
" WARNING: Failed to create symlink after removing existing "
|
"symlink!\n");
|
||||||
"symlink!\n");
|
|
||||||
goto V1_SYMLINK_CREATE_AFTER_1;
|
goto V1_SYMLINK_CREATE_AFTER_1;
|
||||||
} else if (errno == EEXIST) {
|
} else if (errno == EEXIST) {
|
||||||
if ((state->parsed->flags & 8) == 0) {
|
if ((state->parsed->flags & 8) == 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" WARNING: Symlink already exists and "
|
"WARNING: Symlink already exists and "
|
||||||
"\"--overwrite-extract\" is not specified, skipping!\n");
|
"\"--overwrite-extract\" is not specified, skipping!\n");
|
||||||
goto V1_SYMLINK_CREATE_AFTER_1;
|
goto V1_SYMLINK_CREATE_AFTER_1;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(
|
||||||
" NOTICE: Symlink already exists and "
|
stderr,
|
||||||
"\"--overwrite-extract\" specified, attempting to "
|
"NOTICE: Symlink already exists and \"--overwrite-extract\" "
|
||||||
"overwrite...\n");
|
"specified, attempting to overwrite...\n");
|
||||||
unlink(link_name);
|
unlink(link_name);
|
||||||
link_create_retry = 1;
|
link_create_retry = 1;
|
||||||
goto V1_SYMLINK_CREATE_RETRY_1;
|
goto V1_SYMLINK_CREATE_RETRY_1;
|
||||||
|
@ -4081,11 +3795,11 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (errno == EOPNOTSUPP) {
|
if (errno == EOPNOTSUPP) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" NOTICE: Setting permissions of symlink is not supported "
|
"NOTICE: Setting permissions of symlink is not supported "
|
||||||
"by FS/OS!\n");
|
"by FS/OS!\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" WARNING: Failed to set permissions of symlink (%d)!\n",
|
"WARNING: Failed to set permissions of symlink (%d)!\n",
|
||||||
errno);
|
errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4094,7 +3808,7 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
V1_SYMLINK_CREATE_AFTER_1:
|
V1_SYMLINK_CREATE_AFTER_1:
|
||||||
link_create_retry = 1;
|
link_create_retry = 1;
|
||||||
#endif
|
#endif
|
||||||
} else if (!do_extract) {
|
} else {
|
||||||
fprintf(stderr, " Rel path: %s\n", path);
|
fprintf(stderr, " Rel path: %s\n", path);
|
||||||
}
|
}
|
||||||
} else if (!do_extract) {
|
} else if (!do_extract) {
|
||||||
|
@ -4105,9 +3819,6 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
!skip_due_to_invalid) {
|
!skip_due_to_invalid) {
|
||||||
fprintf(stderr, " WARNING: Symlink \"%s\" was not created!\n",
|
fprintf(stderr, " WARNING: Symlink \"%s\" was not created!\n",
|
||||||
link_name);
|
link_name);
|
||||||
} else if (do_extract && link_extracted && !skip_due_to_map &&
|
|
||||||
!skip_due_to_invalid && links_list) {
|
|
||||||
simple_archiver_list_add(links_list, strdup(link_name), NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4208,11 +3919,6 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
simple_archiver_helper_64_bit_be(&u64);
|
simple_archiver_helper_64_bit_be(&u64);
|
||||||
file_info->file_size = u64;
|
file_info->file_size = u64;
|
||||||
|
|
||||||
if (files_map) {
|
|
||||||
simple_archiver_internal_paths_to_files_map(files_map,
|
|
||||||
file_info->filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
simple_archiver_list_add(file_info_list, file_info,
|
simple_archiver_list_add(file_info_list, file_info,
|
||||||
free_internal_file_info);
|
free_internal_file_info);
|
||||||
file_info = NULL;
|
file_info = NULL;
|
||||||
|
@ -4542,10 +4248,6 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_extract && links_list && files_map) {
|
|
||||||
simple_archiver_safe_links_enforce(links_list, files_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SDAS_SUCCESS;
|
return SDAS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4729,69 +4431,3 @@ int simple_archiver_validate_file_path(const char *filepath) {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_archiver_safe_links_enforce(SDArchiverLinkedList *links_list,
|
|
||||||
SDArchiverHashMap *files_map) {
|
|
||||||
uint_fast8_t need_to_print_note = 1;
|
|
||||||
// safe-links: Check that every link maps to a file in the files_map.
|
|
||||||
__attribute__((
|
|
||||||
cleanup(simple_archiver_helper_cleanup_c_string))) char *path_to_cwd =
|
|
||||||
realpath(".", NULL);
|
|
||||||
|
|
||||||
// Ensure path_to_cwd ends with '/'.
|
|
||||||
uint32_t idx = 0;
|
|
||||||
while (path_to_cwd[idx] != 0) {
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
if (path_to_cwd[idx - 1] != '/') {
|
|
||||||
char *temp = malloc(idx + 2);
|
|
||||||
memcpy(temp, path_to_cwd, idx);
|
|
||||||
temp[idx] = '/';
|
|
||||||
temp[idx + 1] = 0;
|
|
||||||
free(path_to_cwd);
|
|
||||||
path_to_cwd = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check every link to make sure it points to an existing file.
|
|
||||||
SDArchiverLLNode *links_node = links_list->head;
|
|
||||||
while (links_node->next != links_list->tail) {
|
|
||||||
links_node = links_node->next;
|
|
||||||
__attribute__((
|
|
||||||
cleanup(simple_archiver_helper_cleanup_c_string))) char *link_realpath =
|
|
||||||
realpath(links_node->data, NULL);
|
|
||||||
if (link_realpath) {
|
|
||||||
// Get local path.
|
|
||||||
__attribute__((cleanup(
|
|
||||||
simple_archiver_helper_cleanup_c_string))) char *link_localpath =
|
|
||||||
simple_archiver_filenames_to_relative_path(path_to_cwd,
|
|
||||||
link_realpath);
|
|
||||||
if (!simple_archiver_hash_map_get(files_map, link_localpath,
|
|
||||||
strlen(link_localpath) + 1)) {
|
|
||||||
// Invalid symlink.
|
|
||||||
fprintf(stderr,
|
|
||||||
"Symlink \"%s\" is invalid (not pointing to archived file), "
|
|
||||||
"removing...\n",
|
|
||||||
(const char *)links_node->data);
|
|
||||||
unlink(links_node->data);
|
|
||||||
if (need_to_print_note) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"NOTE: Disable this behavior with \"--no-safe-links\" if "
|
|
||||||
"needed.\n");
|
|
||||||
need_to_print_note = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Invalid symlink.
|
|
||||||
fprintf(stderr,
|
|
||||||
"Symlink \"%s\" is invalid (failed to resolve), removing...\n",
|
|
||||||
(const char *)links_node->data);
|
|
||||||
unlink(links_node->data);
|
|
||||||
if (need_to_print_note) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"NOTE: Disable this behavior with \"--no-safe-links\" if "
|
|
||||||
"needed.\n");
|
|
||||||
need_to_print_note = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -109,9 +109,4 @@ char *simple_archiver_file_abs_path(const char *filename);
|
||||||
/// Returns 5 if "filepath" is NULL.
|
/// Returns 5 if "filepath" is NULL.
|
||||||
int simple_archiver_validate_file_path(const char *filepath);
|
int simple_archiver_validate_file_path(const char *filepath);
|
||||||
|
|
||||||
/// Removes links from "links_list" in cwd if it is not valid or does not point
|
|
||||||
/// to a file in "files_map".
|
|
||||||
void simple_archiver_safe_links_enforce(SDArchiverLinkedList *links_list,
|
|
||||||
SDArchiverHashMap *files_map);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -76,17 +76,19 @@ int simple_archiver_hash_map_internal_pick_in_list(void *data, void *ud) {
|
||||||
|
|
||||||
uint64_t simple_archiver_hash_default_fn(const void *key, size_t key_size) {
|
uint64_t simple_archiver_hash_default_fn(const void *key, size_t key_size) {
|
||||||
uint64_t seed = 0;
|
uint64_t seed = 0;
|
||||||
uint64_t temp;
|
uint64_t temp = 0;
|
||||||
|
size_t count = 0;
|
||||||
for (size_t idx = 0; idx < key_size; ++idx) {
|
for (size_t idx = 0; idx < key_size; ++idx) {
|
||||||
temp = (uint64_t)(((uint8_t*)key)[idx]) + seed;
|
temp |= ((uint64_t) * ((uint8_t *)key + idx)) << (8 * count);
|
||||||
if (idx % 3 == 0) {
|
++count;
|
||||||
temp ^= 0xA5A538A5A9B5A5A5;
|
if (count >= 8) {
|
||||||
} else if (idx % 3 == 1) {
|
count = 0;
|
||||||
temp ^= 0xD7A58BD7A58BD7AA;
|
seed += temp;
|
||||||
} else {
|
temp = 0;
|
||||||
temp ^= 0x8B7A8B8B87CB8B84;
|
|
||||||
}
|
}
|
||||||
seed += simple_archiver_algo_lcg_defaults(temp);
|
}
|
||||||
|
if (temp != 0) {
|
||||||
|
seed += temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return simple_archiver_algo_lcg_defaults(seed);
|
return simple_archiver_algo_lcg_defaults(seed);
|
||||||
|
@ -104,7 +106,7 @@ int simple_archiver_hash_map_internal_rehash(SDArchiverHashMap *hash_map) {
|
||||||
}
|
}
|
||||||
SDArchiverHashMap new_hash_map;
|
SDArchiverHashMap new_hash_map;
|
||||||
new_hash_map.hash_fn = hash_map->hash_fn;
|
new_hash_map.hash_fn = hash_map->hash_fn;
|
||||||
new_hash_map.buckets_size = (hash_map->buckets_size - 1) * 2 + 1;
|
new_hash_map.buckets_size = hash_map->buckets_size * 2;
|
||||||
// Pointers have the same size (at least on the same machine), so
|
// Pointers have the same size (at least on the same machine), so
|
||||||
// sizeof(void*) should be ok.
|
// sizeof(void*) should be ok.
|
||||||
new_hash_map.buckets = malloc(sizeof(void *) * new_hash_map.buckets_size);
|
new_hash_map.buckets = malloc(sizeof(void *) * new_hash_map.buckets_size);
|
||||||
|
@ -152,7 +154,7 @@ SDArchiverHashMap *simple_archiver_hash_map_init_custom_hasher(
|
||||||
uint64_t (*hash_fn)(const void *, size_t)) {
|
uint64_t (*hash_fn)(const void *, size_t)) {
|
||||||
SDArchiverHashMap *hash_map = malloc(sizeof(SDArchiverHashMap));
|
SDArchiverHashMap *hash_map = malloc(sizeof(SDArchiverHashMap));
|
||||||
hash_map->hash_fn = hash_fn;
|
hash_map->hash_fn = hash_fn;
|
||||||
hash_map->buckets_size = SC_SA_DS_HASH_MAP_START_BUCKET_SIZE + 1;
|
hash_map->buckets_size = SC_SA_DS_HASH_MAP_START_BUCKET_SIZE;
|
||||||
// Pointers have the same size (at least on the same machine), so
|
// Pointers have the same size (at least on the same machine), so
|
||||||
// sizeof(void*) should be ok.
|
// sizeof(void*) should be ok.
|
||||||
hash_map->buckets = malloc(sizeof(void *) * hash_map->buckets_size);
|
hash_map->buckets = malloc(sizeof(void *) * hash_map->buckets_size);
|
||||||
|
|
|
@ -219,59 +219,6 @@ int main(void) {
|
||||||
simple_archiver_hash_map_free(&hash_map);
|
simple_archiver_hash_map_free(&hash_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test hashing.
|
|
||||||
//{
|
|
||||||
// printf("Distribution of 13 over 33...\n");
|
|
||||||
// unsigned int counts[33];
|
|
||||||
// memset(counts, 0, sizeof(unsigned int) * 33);
|
|
||||||
|
|
||||||
// uint64_t hash;
|
|
||||||
|
|
||||||
// hash = simple_archiver_hash_default_fn("/", 2);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/faq", 5);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/faq", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/FAQ", 5);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/FAQ", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/url", 5);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/url", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/home", 6);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/home", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/blog", 6);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/blog", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/test", 6);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/test", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/menu", 6);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/menu", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/posts", 7);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/posts", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/about", 7);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/about", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/media", 7);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/media", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/social", 8);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/social", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
// hash = simple_archiver_hash_default_fn("/projects", 10);
|
|
||||||
// printf("%s in bucket %lu (%lu)\n", "/projects", hash % 33, hash);
|
|
||||||
// counts[hash % 33] += 1;
|
|
||||||
|
|
||||||
// for (unsigned int idx = 0; idx < 33; ++idx) {
|
|
||||||
// printf("Bucket %u: %u\n", idx, counts[idx]);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Test PriorityHeap.
|
// Test PriorityHeap.
|
||||||
{
|
{
|
||||||
SDArchiverPHeap *priority_heap = simple_archiver_priority_heap_init();
|
SDArchiverPHeap *priority_heap = simple_archiver_priority_heap_init();
|
||||||
|
|
16
src/parser.c
16
src/parser.c
|
@ -168,15 +168,6 @@ void simple_archiver_print_usage(void) {
|
||||||
fprintf(stderr, "--overwrite-extract : allows overwriting when extracting\n");
|
fprintf(stderr, "--overwrite-extract : allows overwriting when extracting\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"--no-abs-symlink : do not store absolute paths for symlinks\n");
|
"--no-abs-symlink : do not store absolute paths for symlinks\n");
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"--preserve-symlinks : preserve the symlink's path on archive creation "
|
|
||||||
"instead of deriving abs/relative paths, ignores \"--no-abs-symlink\" "
|
|
||||||
"(It is not recommended to use this option, as absolute-path-symlinks "
|
|
||||||
"may be clobbered on extraction)\n");
|
|
||||||
fprintf(stderr,
|
|
||||||
"--no-safe-links : keep symlinks that link to outside archive "
|
|
||||||
"contents\n");
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"--temp-files-dir <dir> : where to store temporary files created "
|
"--temp-files-dir <dir> : where to store temporary files created "
|
||||||
"when compressing (defaults to current working directory)\n");
|
"when compressing (defaults to current working directory)\n");
|
||||||
|
@ -312,13 +303,6 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
out->flags |= 0x8;
|
out->flags |= 0x8;
|
||||||
} else if (strcmp(argv[0], "--no-abs-symlink") == 0) {
|
} else if (strcmp(argv[0], "--no-abs-symlink") == 0) {
|
||||||
out->flags |= 0x20;
|
out->flags |= 0x20;
|
||||||
} else if (strcmp(argv[0], "--preserve-symlinks") == 0) {
|
|
||||||
out->flags |= 0x100;
|
|
||||||
} else if (strcmp(argv[0], "--no-safe-links") == 0) {
|
|
||||||
out->flags |= 0x80;
|
|
||||||
fprintf(stderr,
|
|
||||||
"NOTICE: Disabling safe-links, symlinks that point to outside "
|
|
||||||
"archived files will be preserved!\n");
|
|
||||||
} else if (strcmp(argv[0], "--temp-files-dir") == 0) {
|
} else if (strcmp(argv[0], "--temp-files-dir") == 0) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
fprintf(stderr, "ERROR: --temp-files-dir is missing an argument!\n");
|
fprintf(stderr, "ERROR: --temp-files-dir is missing an argument!\n");
|
||||||
|
|
|
@ -36,8 +36,6 @@ typedef struct SDArchiverParsed {
|
||||||
/// 0b xxx1 xxxx - Create archive to stdout or read archive from stdin.
|
/// 0b xxx1 xxxx - Create archive to stdout or read archive from stdin.
|
||||||
/// 0b xx1x xxxx - Do not save absolute paths for symlinks.
|
/// 0b xx1x xxxx - Do not save absolute paths for symlinks.
|
||||||
/// 0b x1xx xxxx - Sort files by size before archiving.
|
/// 0b x1xx xxxx - Sort files by size before archiving.
|
||||||
/// 0b 1xxx xxxx - No safe links.
|
|
||||||
/// 0b xxxx xxx1 xxxx xxxx - Preserve symlink target.
|
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
/// Null-terminated string.
|
/// Null-terminated string.
|
||||||
char *filename;
|
char *filename;
|
||||||
|
|
|
@ -256,11 +256,6 @@ int main(void) {
|
||||||
CHECK_STREQ(rel_path, "../other/dir/");
|
CHECK_STREQ(rel_path, "../other/dir/");
|
||||||
simple_archiver_helper_cleanup_c_string(&rel_path);
|
simple_archiver_helper_cleanup_c_string(&rel_path);
|
||||||
|
|
||||||
rel_path = simple_archiver_filenames_to_relative_path(
|
|
||||||
"/one/two/three/", "/one/two/three/four");
|
|
||||||
CHECK_STREQ(rel_path, "four");
|
|
||||||
simple_archiver_helper_cleanup_c_string(&rel_path);
|
|
||||||
|
|
||||||
CHECK_FALSE(simple_archiver_validate_file_path("Local/Path"));
|
CHECK_FALSE(simple_archiver_validate_file_path("Local/Path"));
|
||||||
CHECK_TRUE(simple_archiver_validate_file_path("/Abs/Path"));
|
CHECK_TRUE(simple_archiver_validate_file_path("/Abs/Path"));
|
||||||
CHECK_TRUE(simple_archiver_validate_file_path("Local/../../not/really"));
|
CHECK_TRUE(simple_archiver_validate_file_path("Local/../../not/really"));
|
||||||
|
|
Loading…
Reference in a new issue