Compare commits
16 commits
0f9c8efe63
...
c7cd445139
Author | SHA1 | Date | |
---|---|---|---|
c7cd445139 | |||
b09948d245 | |||
6376be2840 | |||
da18464d5d | |||
8fa430f842 | |||
53fefb7ae8 | |||
45fdffdc9c | |||
7407972450 | |||
3d58f466af | |||
b273d91896 | |||
c71f4f45c7 | |||
c1faae90e9 | |||
d625c1b1cb | |||
a7aa31fc89 | |||
f76e383e78 | |||
efde02b4ab |
7 changed files with 510 additions and 70 deletions
|
@ -83,6 +83,7 @@ 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
|
||||
|
|
|
@ -118,8 +118,16 @@ 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. Currently unused.
|
||||
1. The first bit is "other write permission".
|
||||
2. The second bit is "other execute permission".
|
||||
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.
527
src/archiver.c
527
src/archiver.c
|
@ -767,46 +767,8 @@ 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);
|
||||
|
||||
// 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);
|
||||
rel_path =
|
||||
simple_archiver_filenames_to_relative_path(link_abs_path, abs_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1150,6 +1112,86 @@ 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;
|
||||
|
@ -1229,6 +1271,55 @@ 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) {
|
||||
|
@ -1489,6 +1580,18 @@ 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;
|
||||
|
@ -1666,6 +1769,17 @@ 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);
|
||||
|
@ -1675,17 +1789,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(u16 + 1);
|
||||
malloc((uint32_t)u16 + 1);
|
||||
uint8_t *uc_heap_buf = heap_buf;
|
||||
if (fread(uc_heap_buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) {
|
||||
if (fread(uc_heap_buf, 1, (uint32_t)u16 + 1, in_f) != (size_t)u16 + 1) {
|
||||
return SDAS_INVALID_FILE;
|
||||
}
|
||||
uc_heap_buf[u16 - 1] = 0;
|
||||
uc_heap_buf[u16] = 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 *)buf, "rb");
|
||||
FILE *test_fd = fopen((const char *)uc_heap_buf, "rb");
|
||||
if (test_fd) {
|
||||
skip = 1;
|
||||
fprintf(stderr,
|
||||
|
@ -1696,10 +1810,22 @@ 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 *)buf) + 1);
|
||||
memcpy(out_f_name, buf, strlen((const char *)buf) + 1);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1822,6 +1948,12 @@ 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);
|
||||
|
@ -1830,7 +1962,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) {
|
||||
if (is_compressed && out_f) {
|
||||
// Handle SIGPIPE.
|
||||
signal(SIGPIPE, handle_sig_pipe);
|
||||
|
||||
|
@ -2038,10 +2170,12 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
|||
// Error.
|
||||
return SDAS_INTERNAL_ERROR;
|
||||
}
|
||||
fwrite(buf, 1, fread_ret, out_f);
|
||||
if (ferror(out_f)) {
|
||||
// Error.
|
||||
return SDAS_INTERNAL_ERROR;
|
||||
if (out_f) {
|
||||
fwrite(buf, 1, fread_ret, out_f);
|
||||
if (ferror(out_f)) {
|
||||
// Error.
|
||||
return SDAS_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
compressed_file_size -= fread_ret;
|
||||
} else {
|
||||
|
@ -2050,10 +2184,12 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
|||
// Error.
|
||||
return SDAS_INTERNAL_ERROR;
|
||||
}
|
||||
fwrite(buf, 1, fread_ret, out_f);
|
||||
if (ferror(out_f)) {
|
||||
// Error.
|
||||
return SDAS_INTERNAL_ERROR;
|
||||
if (out_f) {
|
||||
fwrite(buf, 1, fread_ret, out_f);
|
||||
if (ferror(out_f)) {
|
||||
// Error.
|
||||
return SDAS_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
compressed_file_size -= fread_ret;
|
||||
}
|
||||
|
@ -2066,7 +2202,9 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
|
|||
}
|
||||
|
||||
ptrs_array[0] = NULL;
|
||||
fprintf(stderr, " Extracted.\n");
|
||||
if (out_f) {
|
||||
fprintf(stderr, " Extracted.\n");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
while (u64 != 0) {
|
||||
|
@ -2145,26 +2283,108 @@ 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) {
|
||||
if (do_extract && !skip) {
|
||||
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);
|
||||
int_fast8_t retry_symlink = 0;
|
||||
int ret;
|
||||
V0_SYMLINK_CREATE_RETRY_0:
|
||||
ret = symlink(abs_path, out_f_name);
|
||||
if (ret == -1) {
|
||||
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 ret = symlink(rel_path, out_f_name);
|
||||
int_fast8_t retry_symlink = 0;
|
||||
int ret;
|
||||
V0_SYMLINK_CREATE_RETRY_1:
|
||||
ret = symlink(rel_path, out_f_name);
|
||||
if (ret == -1) {
|
||||
return SDAS_FAILED_TO_EXTRACT_SYMLINK;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
|
@ -2175,6 +2395,19 @@ 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 || \
|
||||
|
@ -2184,6 +2417,19 @@ 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(
|
||||
|
@ -2291,6 +2537,13 @@ 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;
|
||||
|
||||
|
@ -2312,6 +2565,13 @@ 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 &&
|
||||
|
@ -2340,12 +2600,49 @@ 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);
|
||||
|
@ -2373,12 +2670,49 @@ 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);
|
||||
|
@ -2434,6 +2768,27 @@ 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;
|
||||
}
|
||||
|
@ -2872,3 +3227,53 @@ 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;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ typedef struct SDArchiverState {
|
|||
size_t digits;
|
||||
} SDArchiverState;
|
||||
|
||||
enum SDArchiverStateReturns {
|
||||
typedef enum SDArchiverStateReturns {
|
||||
SDAS_SUCCESS = 0,
|
||||
SDAS_HEADER_ALREADY_WRITTEN = 1,
|
||||
SDAS_FAILED_TO_WRITE,
|
||||
|
@ -53,7 +53,7 @@ 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,4 +88,8 @@ 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
|
||||
|
|
18
src/main.c
18
src/main.c
|
@ -97,7 +97,8 @@ 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(ret);
|
||||
char *error_str =
|
||||
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
|
||||
fprintf(stderr, " %s\n", error_str);
|
||||
}
|
||||
fclose(file);
|
||||
|
@ -113,7 +114,8 @@ 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(ret);
|
||||
char *error_str =
|
||||
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
|
||||
fprintf(stderr, " %s\n", error_str);
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +132,8 @@ 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(ret);
|
||||
char *error_str =
|
||||
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
|
||||
fprintf(stderr, " %s\n", error_str);
|
||||
}
|
||||
fclose(file);
|
||||
|
@ -138,7 +141,8 @@ 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(ret);
|
||||
char *error_str =
|
||||
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
|
||||
fprintf(stderr, " %s\n", error_str);
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +161,8 @@ 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(ret);
|
||||
char *error_str =
|
||||
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
|
||||
fprintf(stderr, " %s\n", error_str);
|
||||
}
|
||||
fclose(file);
|
||||
|
@ -165,7 +170,8 @@ 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(ret);
|
||||
char *error_str =
|
||||
simple_archiver_error_to_string((SDArchiverStateReturns)ret);
|
||||
fprintf(stderr, " %s\n", error_str);
|
||||
}
|
||||
}
|
||||
|
|
16
src/test.c
16
src/test.c
|
@ -23,6 +23,7 @@
|
|||
#include <string.h>
|
||||
|
||||
// Local includes.
|
||||
#include "archiver.h"
|
||||
#include "helpers.h"
|
||||
#include "parser_internal.h"
|
||||
|
||||
|
@ -241,6 +242,21 @@ 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;
|
||||
|
|
Loading…
Reference in a new issue