Compare commits

..

13 commits

Author SHA1 Message Date
0f9c8efe63 Add support for writing multiple file formats
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 5s
2024-10-02 11:38:39 +09:00
f89e5f7640 Test/fix symlink test/extract in v1 file format
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 11s
2024-09-30 19:17:57 +09:00
0ae80168e3 Fix v1 archive decompression
Previous implementation sent too many bytes to decompressor if size was
less than 1024.
2024-09-30 19:17:57 +09:00
d93f62a0cb Remove unnecessary printf used for testing 2024-09-30 19:17:57 +09:00
8f33d62392 Impl. extract with decompressor file format v1 2024-09-30 19:17:57 +09:00
52bbfa4e65 v1 extract skip non-specified args if exists 2024-09-30 19:17:57 +09:00
8bedc750ba Impl. setting stored UID/GID if EUID 0 2024-09-30 19:17:57 +09:00
aaebe09347 "Fix" Linux/Mac/Unix usage 2024-09-30 19:17:57 +09:00
0a776cae37 Impl. simple test/extract new file format (WIP)
TODO:
    Extract symlinks in new format (implemented but untested).
    Extract compressed files in new format.
2024-09-30 19:17:57 +09:00
f472ad1a6b Split up handling of archive file based on version 2024-09-30 19:17:57 +09:00
dcd2e531e6 Fix typo 2024-09-30 19:17:57 +09:00
ef49b37648 Fix typo in file format specification version 1 2024-09-30 19:17:57 +09:00
6ad609e7fc Create file format for format version 1
This is in preparation of improving compression by concatenating files
together before compressing them to reduce the per-file overhead.
2024-09-30 19:17:57 +09:00
7 changed files with 70 additions and 510 deletions

View file

@ -83,7 +83,6 @@ add_executable(test_simplearchiver
src/test.c
src/parser.c
src/helpers.c
src/archiver.c
src/algorithms/linear_congruential_gen.c
src/data_structures/linked_list.c
src/data_structures/hash_map.c

View file

@ -118,16 +118,8 @@ Following the link-count bytes, the following bytes are added for each symlink:
1. The first byte.
1. The first bit is UNSET if relative links are preferred, and is SET if
absolute links are preferred.
2. The second bit is "user read permission".
3. The third bit is "user write permission".
4. The fourth bit is "user execute permission".
5. The fifth bit is "group read permission".
6. The sixth bit is "group write permission".
7. The seventh bit is "group execute permission".
8. The eighth bit is "other read permission".
2. The second byte.
1. The first bit is "other write permission".
2. The second bit is "other execute permission".
1. Currently unused.
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.
3. X bytes of link-name (length defined by previous value). Is a NULL-terminated

Binary file not shown.

View file

@ -767,8 +767,46 @@ int write_files_fn(void *data, void *ud) {
// 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, abs_path);
// Compare paths to get relative path.
// Get first non-common char.
size_t idx;
size_t last_slash;
for (idx = 0, last_slash = 0;
idx < strlen(abs_path) && idx < strlen(link_abs_path); ++idx) {
if (((const char *)abs_path)[idx] !=
((const char *)link_abs_path)[idx]) {
break;
} else if (((const char *)abs_path)[idx] == '/') {
last_slash = idx + 1;
}
}
// Get substrings of both paths.
char *link_substr = (char *)link_abs_path + last_slash;
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);
// Generate the relative path.
int_fast8_t 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);
}
}
@ -1112,86 +1150,6 @@ void cleanup_internal_file_info(SDArchiverInternalFileInfo **file_info) {
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
mode_t permissions_from_bits_v1_symlink(const uint8_t flags[2],
uint_fast8_t print) {
mode_t permissions = 0;
if ((flags[0] & 2) != 0) {
permissions |= S_IRUSR;
if (print) {
fprintf(stderr, "r");
}
} else if (print) {
fprintf(stderr, "-");
}
if ((flags[0] & 4) != 0) {
permissions |= S_IWUSR;
if (print) {
fprintf(stderr, "w");
}
} else if (print) {
fprintf(stderr, "-");
}
if ((flags[0] & 8) != 0) {
permissions |= S_IXUSR;
if (print) {
fprintf(stderr, "x");
}
} else if (print) {
fprintf(stderr, "-");
}
if ((flags[0] & 0x10) != 0) {
permissions |= S_IRGRP;
if (print) {
fprintf(stderr, "r");
}
} else if (print) {
fprintf(stderr, "-");
}
if ((flags[0] & 0x20) != 0) {
permissions |= S_IWGRP;
if (print) {
fprintf(stderr, "w");
}
} else if (print) {
fprintf(stderr, "-");
}
if ((flags[0] & 0x40) != 0) {
permissions |= S_IXGRP;
if (print) {
fprintf(stderr, "x");
}
} else if (print) {
fprintf(stderr, "-");
}
if ((flags[0] & 0x80) != 0) {
permissions |= S_IROTH;
if (print) {
fprintf(stderr, "r");
}
} else if (print) {
fprintf(stderr, "-");
}
if ((flags[1] & 1) != 0) {
permissions |= S_IWOTH;
if (print) {
fprintf(stderr, "w");
}
} else if (print) {
fprintf(stderr, "-");
}
if ((flags[1] & 2) != 0) {
permissions |= S_IXOTH;
if (print) {
fprintf(stderr, "x");
}
} else if (print) {
fprintf(stderr, "-");
}
return permissions;
}
mode_t permissions_from_bits_version_1(const uint8_t flags[4],
uint_fast8_t print) {
mode_t permissions = 0;
@ -1271,55 +1229,6 @@ mode_t permissions_from_bits_version_1(const uint8_t flags[4],
return permissions;
}
void print_permissions(mode_t permissions) {
if ((permissions & S_IRUSR)) {
fprintf(stderr, "r");
} else {
fprintf(stderr, "-");
}
if ((permissions & S_IWUSR)) {
fprintf(stderr, "w");
} else {
fprintf(stderr, "-");
}
if ((permissions & S_IXUSR)) {
fprintf(stderr, "x");
} else {
fprintf(stderr, "-");
}
if ((permissions & S_IRGRP)) {
fprintf(stderr, "r");
} else {
fprintf(stderr, "-");
}
if ((permissions & S_IWGRP)) {
fprintf(stderr, "w");
} else {
fprintf(stderr, "-");
}
if ((permissions & S_IXGRP)) {
fprintf(stderr, "x");
} else {
fprintf(stderr, "-");
}
if ((permissions & S_IROTH)) {
fprintf(stderr, "r");
} else {
fprintf(stderr, "-");
}
if ((permissions & S_IWOTH)) {
fprintf(stderr, "w");
} else {
fprintf(stderr, "-");
}
if ((permissions & S_IXOTH)) {
fprintf(stderr, "x");
} else {
fprintf(stderr, "-");
}
}
#endif
void simple_archiver_internal_cleanup_int_fd(int *fd) {
@ -1580,18 +1489,6 @@ int simple_archiver_write_v0(FILE *out_f, SDArchiverState *state,
int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
const SDArchiverLinkedList *filenames) {
// 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();
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);
return SDAS_FAILED_TO_CREATE_MAP;
}
free(ptr_array);
// TODO Impl.
fprintf(stderr, "Writing v1 unimplemented\n");
return SDAS_INTERNAL_ERROR;
@ -1769,17 +1666,6 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
}
} else {
skip = 0;
int fd = open((const char *)buf, O_RDONLY | O_NOFOLLOW);
if (fd == -1) {
if (errno == ELOOP) {
// Is an existing symbolic file.
unlink((const char *)buf);
}
} else {
close(fd);
// Is an existing file.
unlink((const char *)buf);
}
}
if (!skip) {
out_f_name = malloc(strlen((const char *)buf) + 1);
@ -1789,17 +1675,17 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
} else {
__attribute__((
cleanup(simple_archiver_helper_cleanup_malloced))) void *heap_buf =
malloc((uint32_t)u16 + 1);
malloc(u16 + 1);
uint8_t *uc_heap_buf = heap_buf;
if (fread(uc_heap_buf, 1, (uint32_t)u16 + 1, in_f) != (size_t)u16 + 1) {
if (fread(uc_heap_buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
return SDAS_INVALID_FILE;
}
uc_heap_buf[u16] = 0;
uc_heap_buf[u16 - 1] = 0;
fprintf(stderr, " Filename: %s\n", uc_heap_buf);
if (do_extract) {
if ((state->parsed->flags & 0x8) == 0) {
__attribute__((cleanup(simple_archiver_helper_cleanup_FILE)))
FILE *test_fd = fopen((const char *)uc_heap_buf, "rb");
FILE *test_fd = fopen((const char *)buf, "rb");
if (test_fd) {
skip = 1;
fprintf(stderr,
@ -1810,22 +1696,10 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
}
} else {
skip = 0;
int fd = open((const char *)uc_heap_buf, O_RDONLY | O_NOFOLLOW);
if (fd == -1) {
if (errno == ELOOP) {
// Is an existing symbolic file.
unlink((const char *)uc_heap_buf);
}
} else {
close(fd);
// Is an existing file.
unlink((const char *)uc_heap_buf);
}
}
if (!skip) {
out_f_name = malloc(strlen((const char *)uc_heap_buf) + 1);
memcpy(out_f_name, uc_heap_buf,
strlen((const char *)uc_heap_buf) + 1);
out_f_name = malloc(strlen((const char *)buf) + 1);
memcpy(out_f_name, buf, strlen((const char *)buf) + 1);
}
}
}
@ -1948,12 +1822,6 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
simple_archiver_helper_make_dirs((const char *)out_f_name);
out_f = fopen(out_f_name, "wb");
if (!out_f) {
fprintf(stderr,
"WARNING: Failed to open \"%s\" for writing! (No write "
"permissions?)\n",
(char *)out_f_name);
}
__attribute__((
cleanup(cleanup_temp_filename_delete))) void **ptrs_array =
malloc(sizeof(void *) * 2);
@ -1962,7 +1830,7 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
if (is_compressed && out_f) {
if (is_compressed) {
// Handle SIGPIPE.
signal(SIGPIPE, handle_sig_pipe);
@ -2170,12 +2038,10 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
// Error.
return SDAS_INTERNAL_ERROR;
}
if (out_f) {
fwrite(buf, 1, fread_ret, out_f);
if (ferror(out_f)) {
// Error.
return SDAS_INTERNAL_ERROR;
}
fwrite(buf, 1, fread_ret, out_f);
if (ferror(out_f)) {
// Error.
return SDAS_INTERNAL_ERROR;
}
compressed_file_size -= fread_ret;
} else {
@ -2184,12 +2050,10 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
// Error.
return SDAS_INTERNAL_ERROR;
}
if (out_f) {
fwrite(buf, 1, fread_ret, out_f);
if (ferror(out_f)) {
// Error.
return SDAS_INTERNAL_ERROR;
}
fwrite(buf, 1, fread_ret, out_f);
if (ferror(out_f)) {
// Error.
return SDAS_INTERNAL_ERROR;
}
compressed_file_size -= fread_ret;
}
@ -2202,9 +2066,7 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
}
ptrs_array[0] = NULL;
if (out_f) {
fprintf(stderr, " Extracted.\n");
}
fprintf(stderr, " Extracted.\n");
#endif
} else {
while (u64 != 0) {
@ -2283,108 +2145,26 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
fprintf(stderr, " Link relative path: %s\n", (char *)rel_path);
}
if (do_extract && !skip) {
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_fast8_t retry_symlink = 0;
int ret;
V0_SYMLINK_CREATE_RETRY_0:
ret = symlink(abs_path, out_f_name);
int ret = symlink(abs_path, out_f_name);
if (ret == -1) {
if (retry_symlink) {
fprintf(stderr,
"WARNING: Failed to create symlink after removing "
"existing symlink!\n");
goto V0_SYMLINK_CREATE_AFTER_0;
} else if (errno == EEXIST) {
if ((state->parsed->flags & 8) == 0) {
fprintf(
stderr,
"WARNING: Symlink already exists and "
"\"--overwrite-extract\" is not specified, skipping!\n");
goto V0_SYMLINK_CREATE_AFTER_0;
} else {
fprintf(stderr,
"NOTICE: Symlink already exists and "
"\"--overwrite-extract\" specified, attempting to "
"overwrite...\n");
unlink(out_f_name);
retry_symlink = 1;
goto V0_SYMLINK_CREATE_RETRY_0;
}
} else {
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
}
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
}
ret = fchmodat(AT_FDCWD, out_f_name, permissions,
AT_SYMLINK_NOFOLLOW);
if (ret == -1) {
if (errno == EOPNOTSUPP) {
fprintf(stderr,
"NOTICE: Setting permissions of symlink is not "
"supported by FS/OS!\n");
} else {
fprintf(stderr,
"WARNING: Failed to set permissions of symlink (%d)!\n",
errno);
}
}
V0_SYMLINK_CREATE_AFTER_0:
retry_symlink = 1;
#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_fast8_t retry_symlink = 0;
int ret;
V0_SYMLINK_CREATE_RETRY_1:
ret = symlink(rel_path, out_f_name);
int ret = symlink(rel_path, out_f_name);
if (ret == -1) {
if (retry_symlink) {
fprintf(stderr,
"WARNING: Failed to create symlink after removing "
"existing symlink!\n");
goto V0_SYMLINK_CREATE_AFTER_1;
} else if (errno == EEXIST) {
if ((state->parsed->flags & 8) == 0) {
fprintf(
stderr,
"WARNING: Symlink already exists and "
"\"--overwrite-extract\" is not specified, skipping!\n");
goto V0_SYMLINK_CREATE_AFTER_1;
} else {
fprintf(stderr,
"NOTICE: Symlink already exists and "
"\"--overwrite-extract\" specified, attempting to "
"overwrite...\n");
unlink(out_f_name);
retry_symlink = 1;
goto V0_SYMLINK_CREATE_RETRY_1;
}
} else {
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
}
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
}
ret = fchmodat(AT_FDCWD, out_f_name, permissions,
AT_SYMLINK_NOFOLLOW);
if (ret == -1) {
if (errno == EOPNOTSUPP) {
fprintf(stderr,
"NOTICE: Setting permissions of symlink is not "
"supported by FS/OS!\n");
} else {
fprintf(stderr,
"WARNING: Failed to set permissions of symlink (%d)!\n",
errno);
}
}
V0_SYMLINK_CREATE_AFTER_1:
retry_symlink = 1;
#endif
}
} else if (abs_path) {
@ -2395,19 +2175,6 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
if (ret == -1) {
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
}
ret =
fchmodat(AT_FDCWD, out_f_name, permissions, AT_SYMLINK_NOFOLLOW);
if (ret == -1) {
if (errno == EOPNOTSUPP) {
fprintf(stderr,
"NOTICE: Setting permissions of symlink is not supported "
"by FS/OS!\n");
} else {
fprintf(stderr,
"WARNING: Failed to set permissions of symlink (%d)!\n",
errno);
}
}
#endif
} else if (rel_path) {
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
@ -2417,19 +2184,6 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
if (ret == -1) {
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
}
ret =
fchmodat(AT_FDCWD, out_f_name, permissions, AT_SYMLINK_NOFOLLOW);
if (ret == -1) {
if (errno == EOPNOTSUPP) {
fprintf(stderr,
"NOTICE: Setting permissions of symlink is not supported "
"by FS/OS!\n");
} else {
fprintf(stderr,
"WARNING: Failed to set permissions of symlink (%d)!\n",
errno);
}
}
#endif
} else {
fprintf(
@ -2537,13 +2291,6 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
return SDAS_INVALID_FILE;
}
const uint_fast8_t absolute_preferred = (buf[0] & 1) ? 1 : 0;
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
mode_t permissions = permissions_from_bits_v1_symlink(buf, 0);
#endif
uint_fast8_t link_extracted = 0;
uint_fast8_t skip_due_to_map = 0;
@ -2565,13 +2312,6 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
if (!do_extract) {
fprintf(stderr, " Link name: %s\n", link_name);
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
fprintf(stderr, " Link Permissions: ");
print_permissions(permissions);
fprintf(stderr, "\n");
#endif
}
if (working_files_map &&
@ -2600,49 +2340,12 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
simple_archiver_helper_make_dirs(link_name);
int_fast8_t link_create_retry = 0;
V1_SYMLINK_CREATE_RETRY_0:
ret = symlink(path, link_name);
if (ret == -1) {
if (link_create_retry) {
fprintf(stderr,
"WARNING: Failed to create symlink after removing existing "
"symlink!\n");
goto V1_SYMLINK_CREATE_AFTER_0;
} else if (errno == EEXIST) {
if ((state->parsed->flags & 8) == 0) {
fprintf(stderr,
"WARNING: Symlink already exists and "
"\"--overwrite-extract\" is not specified, skipping!\n");
goto V1_SYMLINK_CREATE_AFTER_0;
} else {
fprintf(
stderr,
"NOTICE: Symlink already exists and \"--overwrite-extract\" "
"specified, attempting to overwrite...\n");
unlink(link_name);
link_create_retry = 1;
goto V1_SYMLINK_CREATE_RETRY_0;
}
}
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
}
ret = fchmodat(AT_FDCWD, link_name, permissions, AT_SYMLINK_NOFOLLOW);
if (ret == -1) {
if (errno == EOPNOTSUPP) {
fprintf(stderr,
"NOTICE: Setting permissions of symlink is not supported "
"by FS/OS!\n");
} else {
fprintf(stderr,
"WARNING: Failed to set permissions of symlink (%d)!\n",
errno);
}
}
link_extracted = 1;
fprintf(stderr, " %s -> %s\n", link_name, path);
V1_SYMLINK_CREATE_AFTER_0:
link_create_retry = 1;
#endif
} else {
fprintf(stderr, " Abs path: %s\n", path);
@ -2670,49 +2373,12 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
simple_archiver_helper_make_dirs(link_name);
int_fast8_t link_create_retry = 0;
V1_SYMLINK_CREATE_RETRY_1:
ret = symlink(path, link_name);
if (ret == -1) {
if (link_create_retry) {
fprintf(stderr,
"WARNING: Failed to create symlink after removing existing "
"symlink!\n");
goto V1_SYMLINK_CREATE_AFTER_1;
} else if (errno == EEXIST) {
if ((state->parsed->flags & 8) == 0) {
fprintf(stderr,
"WARNING: Symlink already exists and "
"\"--overwrite-extract\" is not specified, skipping!\n");
goto V1_SYMLINK_CREATE_AFTER_1;
} else {
fprintf(
stderr,
"NOTICE: Symlink already exists and \"--overwrite-extract\" "
"specified, attempting to overwrite...\n");
unlink(link_name);
link_create_retry = 1;
goto V1_SYMLINK_CREATE_RETRY_1;
}
}
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
}
ret = fchmodat(AT_FDCWD, link_name, permissions, AT_SYMLINK_NOFOLLOW);
if (ret == -1) {
if (errno == EOPNOTSUPP) {
fprintf(stderr,
"NOTICE: Setting permissions of symlink is not supported "
"by FS/OS!\n");
} else {
fprintf(stderr,
"WARNING: Failed to set permissions of symlink (%d)!\n",
errno);
}
}
link_extracted = 1;
fprintf(stderr, " %s -> %s\n", link_name, path);
V1_SYMLINK_CREATE_AFTER_1:
link_create_retry = 1;
#endif
} else {
fprintf(stderr, " Rel path: %s\n", path);
@ -2768,27 +2434,6 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
}
file_info->filename[u16] = 0;
if (state && state->parsed && (state->parsed->flags & 8) != 0) {
int fd = open((const char *)buf, O_RDONLY | O_NOFOLLOW);
if (fd == -1) {
if (errno == ELOOP) {
// Exists as a symlink.
fprintf(stderr,
"WARNING: Filename \"%s\" already exists as symlink, "
"removing...\n",
(const char *)buf);
unlink((const char *)buf);
} else {
// File doesn't exist, do nothing.
}
} else {
close(fd);
fprintf(stderr, "WARNING: File \"%s\" already exists, removing...\n",
(const char *)buf);
unlink((const char *)buf);
}
}
if (fread(file_info->bit_flags, 1, 4, in_f) != 4) {
return SDAS_INVALID_FILE;
}
@ -3227,53 +2872,3 @@ int simple_archiver_de_compress(int pipe_fd_in[2], int pipe_fd_out[2],
return 1;
#endif
}
char *simple_archiver_filenames_to_relative_path(const char *from_abs,
const char *to_abs) {
if (!from_abs || !to_abs) {
return NULL;
}
// Get first non-common char and last slash before it.
uint_fast32_t idx;
uint_fast32_t last_slash;
for (idx = 0, last_slash = 0; idx < strlen(from_abs) && idx < strlen(to_abs);
++idx) {
if (((const char *)to_abs)[idx] != ((const char *)from_abs)[idx]) {
break;
} else if (((const char *)to_abs)[idx] == '/') {
last_slash = idx + 1;
}
}
// Get substrings of both paths.
char *link_substr = (char *)from_abs + last_slash;
char *dest_substr = (char *)to_abs + last_slash;
char *rel_path = malloc(strlen(dest_substr) + 1);
strncpy(rel_path, dest_substr, strlen(dest_substr) + 1);
// fprintf(stderr, "DEBUG: link_substr \"%s\", dest_substr \"%s\"\n",
// link_substr, dest_substr);
// Get the relative path finally.
int_fast8_t 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);
return rel_path;
}

View file

@ -40,7 +40,7 @@ typedef struct SDArchiverState {
size_t digits;
} SDArchiverState;
typedef enum SDArchiverStateReturns {
enum SDArchiverStateReturns {
SDAS_SUCCESS = 0,
SDAS_HEADER_ALREADY_WRITTEN = 1,
SDAS_FAILED_TO_WRITE,
@ -53,7 +53,7 @@ typedef enum SDArchiverStateReturns {
SDAS_FAILED_TO_EXTRACT_SYMLINK,
SDAS_FAILED_TO_CHANGE_CWD,
SDAS_INVALID_WRITE_VERSION
} SDArchiverStateReturns;
};
/// Returned pointer must not be freed.
char *simple_archiver_error_to_string(enum SDArchiverStateReturns error);
@ -88,8 +88,4 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
int simple_archiver_de_compress(int pipe_fd_in[2], int pipe_fd_out[2],
const char *cmd, void *pid_out);
/// If returns non-NULL, must be free'd.
char *simple_archiver_filenames_to_relative_path(const char *from_abs,
const char *to_abs);
#endif

View file

@ -97,8 +97,7 @@ int main(int argc, const char **argv) {
int ret = simple_archiver_write_all(file, state, filenames);
if (ret != SDAS_SUCCESS) {
fprintf(stderr, "Error during writing.\n");
char *error_str =
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
char *error_str = simple_archiver_error_to_string(ret);
fprintf(stderr, " %s\n", error_str);
}
fclose(file);
@ -114,8 +113,7 @@ int main(int argc, const char **argv) {
int ret = simple_archiver_write_all(stdout, state, filenames);
if (ret != SDAS_SUCCESS) {
fprintf(stderr, "Error during writing.\n");
char *error_str =
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
char *error_str = simple_archiver_error_to_string(ret);
fprintf(stderr, " %s\n", error_str);
}
}
@ -132,8 +130,7 @@ int main(int argc, const char **argv) {
int ret = simple_archiver_parse_archive_info(file, 0, NULL);
if (ret != 0) {
fprintf(stderr, "Error during archive checking/examining.\n");
char *error_str =
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
char *error_str = simple_archiver_error_to_string(ret);
fprintf(stderr, " %s\n", error_str);
}
fclose(file);
@ -141,8 +138,7 @@ int main(int argc, const char **argv) {
int ret = simple_archiver_parse_archive_info(stdin, 0, NULL);
if (ret != 0) {
fprintf(stderr, "Error during archive checking/examining.\n");
char *error_str =
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
char *error_str = simple_archiver_error_to_string(ret);
fprintf(stderr, " %s\n", error_str);
}
}
@ -161,8 +157,7 @@ int main(int argc, const char **argv) {
int ret = simple_archiver_parse_archive_info(file, 1, state);
if (ret != SDAS_SUCCESS) {
fprintf(stderr, "Error during archive extracting.\n");
char *error_str =
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
char *error_str = simple_archiver_error_to_string(ret);
fprintf(stderr, " %s\n", error_str);
}
fclose(file);
@ -170,8 +165,7 @@ int main(int argc, const char **argv) {
int ret = simple_archiver_parse_archive_info(stdin, 1, state);
if (ret != SDAS_SUCCESS) {
fprintf(stderr, "Error during archive extracting.\n");
char *error_str =
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
char *error_str = simple_archiver_error_to_string(ret);
fprintf(stderr, " %s\n", error_str);
}
}

View file

@ -23,7 +23,6 @@
#include <string.h>
// Local includes.
#include "archiver.h"
#include "helpers.h"
#include "parser_internal.h"
@ -242,21 +241,6 @@ int main(void) {
free(out);
}
// Test archiver.
{
__attribute__((
cleanup(simple_archiver_helper_cleanup_c_string))) char *rel_path =
simple_archiver_filenames_to_relative_path(
"/one/two/three/four/five", "/one/two/branch/other/path");
CHECK_STREQ(rel_path, "../../branch/other/path");
simple_archiver_helper_cleanup_c_string(&rel_path);
rel_path = simple_archiver_filenames_to_relative_path(
"/one/two/three/four/five", "/one/two/three/other/dir/");
CHECK_STREQ(rel_path, "../other/dir/");
simple_archiver_helper_cleanup_c_string(&rel_path);
}
printf("Checks checked: %u\n", checks_checked);
printf("Checks passed: %u\n", checks_passed);
return checks_passed == checks_checked ? 0 : 1;