Refactorings for v1 extract, other refactorings
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 5s

This commit is contained in:
Stephen Seo 2024-10-02 15:10:22 +09:00
parent b09948d245
commit c7cd445139
5 changed files with 273 additions and 9 deletions

View file

@ -118,8 +118,16 @@ Following the link-count bytes, the following bytes are added for each symlink:
1. The first byte. 1. The first byte.
1. The first bit is UNSET if relative links are preferred, and is SET if 1. The first bit is UNSET if relative links are preferred, and is SET if
absolute links are preferred. 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. 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 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

Binary file not shown.

View file

@ -1112,6 +1112,86 @@ void cleanup_internal_file_info(SDArchiverInternalFileInfo **file_info) {
#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
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], mode_t permissions_from_bits_version_1(const uint8_t flags[4],
uint_fast8_t print) { uint_fast8_t print) {
mode_t permissions = 0; mode_t permissions = 0;
@ -1191,6 +1271,55 @@ mode_t permissions_from_bits_version_1(const uint8_t flags[4],
return permissions; 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 #endif
void simple_archiver_internal_cleanup_int_fd(int *fd) { void simple_archiver_internal_cleanup_int_fd(int *fd) {
@ -1451,6 +1580,18 @@ int simple_archiver_write_v0(FILE *out_f, SDArchiverState *state,
int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state, int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
const SDArchiverLinkedList *filenames) { 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. // TODO Impl.
fprintf(stderr, "Writing v1 unimplemented\n"); fprintf(stderr, "Writing v1 unimplemented\n");
return SDAS_INTERNAL_ERROR; return SDAS_INTERNAL_ERROR;
@ -2396,6 +2537,13 @@ 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;
#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 link_extracted = 0;
uint_fast8_t skip_due_to_map = 0; uint_fast8_t skip_due_to_map = 0;
@ -2417,6 +2565,13 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
if (!do_extract) { if (!do_extract) {
fprintf(stderr, " Link name: %s\n", link_name); 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 && if (working_files_map &&
@ -2445,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_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
simple_archiver_helper_make_dirs(link_name); simple_archiver_helper_make_dirs(link_name);
int_fast8_t link_create_retry = 0;
V1_SYMLINK_CREATE_RETRY_0:
ret = symlink(path, link_name); ret = symlink(path, link_name);
if (ret == -1) { 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; 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; link_extracted = 1;
fprintf(stderr, " %s -> %s\n", link_name, path); fprintf(stderr, " %s -> %s\n", link_name, path);
V1_SYMLINK_CREATE_AFTER_0:
link_create_retry = 1;
#endif #endif
} else { } else {
fprintf(stderr, " Abs path: %s\n", path); fprintf(stderr, " Abs path: %s\n", path);
@ -2478,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_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
simple_archiver_helper_make_dirs(link_name); simple_archiver_helper_make_dirs(link_name);
int_fast8_t link_create_retry = 0;
V1_SYMLINK_CREATE_RETRY_1:
ret = symlink(path, link_name); ret = symlink(path, link_name);
if (ret == -1) { 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; 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; link_extracted = 1;
fprintf(stderr, " %s -> %s\n", link_name, path); fprintf(stderr, " %s -> %s\n", link_name, path);
V1_SYMLINK_CREATE_AFTER_1:
link_create_retry = 1;
#endif #endif
} else { } else {
fprintf(stderr, " Rel path: %s\n", path); fprintf(stderr, " Rel path: %s\n", path);
@ -2539,6 +2768,27 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
} }
file_info->filename[u16] = 0; 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) { if (fread(file_info->bit_flags, 1, 4, in_f) != 4) {
return SDAS_INVALID_FILE; return SDAS_INVALID_FILE;
} }

View file

@ -40,7 +40,7 @@ typedef struct SDArchiverState {
size_t digits; size_t digits;
} SDArchiverState; } SDArchiverState;
enum SDArchiverStateReturns { typedef enum SDArchiverStateReturns {
SDAS_SUCCESS = 0, SDAS_SUCCESS = 0,
SDAS_HEADER_ALREADY_WRITTEN = 1, SDAS_HEADER_ALREADY_WRITTEN = 1,
SDAS_FAILED_TO_WRITE, SDAS_FAILED_TO_WRITE,
@ -53,7 +53,7 @@ enum SDArchiverStateReturns {
SDAS_FAILED_TO_EXTRACT_SYMLINK, SDAS_FAILED_TO_EXTRACT_SYMLINK,
SDAS_FAILED_TO_CHANGE_CWD, SDAS_FAILED_TO_CHANGE_CWD,
SDAS_INVALID_WRITE_VERSION SDAS_INVALID_WRITE_VERSION
}; } SDArchiverStateReturns;
/// Returned pointer must not be freed. /// Returned pointer must not be freed.
char *simple_archiver_error_to_string(enum SDArchiverStateReturns error); char *simple_archiver_error_to_string(enum SDArchiverStateReturns error);

View file

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