const struct file_archive_file_backend* file_archive_get_file_backend(const char *path) { char newpath[PATH_MAX_LENGTH]; const char *file_ext = NULL; char *last = NULL; newpath[0] = '\0'; strlcpy(newpath, path, sizeof(newpath)); last = (char*)path_get_archive_delim(newpath); if (last) *last = '\0'; file_ext = path_get_extension(newpath); #ifdef HAVE_7ZIP if (string_is_equal_noncase(file_ext, "7z")) return &sevenzip_backend; #endif #ifdef HAVE_ZLIB if ( string_is_equal_noncase(file_ext, "zip") || string_is_equal_noncase(file_ext, "apk") ) return &zlib_backend; #endif return NULL; }
/** * file_archive_filename_split: * @str : filename to turn into a string list * * Creates a new string list based on filename @path, delimited by a hash (#). * * Returns: new string list if successful, otherwise NULL. */ static struct string_list *file_archive_filename_split(const char *path) { union string_list_elem_attr attr; struct string_list *list = string_list_new(); const char *delim = path_get_archive_delim(path); memset(&attr, 0, sizeof(attr)); if (delim) { /* add archive path to list first */ if (!string_list_append_n(list, path, delim - path, attr)) goto error; /* now add the path within the archive */ delim++; if (*delim) { if (!string_list_append(list, delim, attr)) goto error; } } else if (!string_list_append(list, path, attr)) goto error; return list; error: string_list_free(list); return NULL; }
static int file_archive_parse_file_init(file_archive_transfer_t *state, const char *file) { char path[PATH_MAX_LENGTH]; char *last = NULL; path[0] = '\0'; strlcpy(path, file, sizeof(path)); last = (char*)path_get_archive_delim(path); if (last) *last = '\0'; state->backend = file_archive_get_file_backend(path); if (!state->backend) return -1; state->handle = file_archive_open(path); if (!state->handle) return -1; state->archive_size = file_archive_size(state->handle); state->data = file_archive_data(state->handle); state->footer = 0; state->directory = 0; return state->backend->archive_parse_file_init(state, path); }
bool core_info_database_supports_content_path(const char *database_path, const char *path) { size_t i; char *database = NULL; const char *delim = NULL; const char *archive_path = NULL; if (!core_info_curr_list) return false; database = strdup(path_basename(database_path)); path_remove_extension(database); delim = path_get_archive_delim(path); if (delim) archive_path = delim - 1; /* if the path contains a compressed file and the core supports archives, * we don't want to look at this file */ if (archive_path) { for (i = 0; i < core_info_curr_list->count; i++) { const core_info_t *info = &core_info_curr_list->list[i]; if (!string_list_find_elem(info->databases_list, database)) continue; if ( !string_list_find_elem(info->supported_extensions_list, "zip") && !string_list_find_elem(info->supported_extensions_list, "7z")) continue; free(database); return false; } } for (i = 0; i < core_info_curr_list->count; i++) { const core_info_t *info = &core_info_curr_list->list[i]; if (!string_list_find_elem(info->supported_extensions_list, path_get_extension(path))) continue; if (!string_list_find_elem(info->databases_list, database)) continue; free(database); return true; } free(database); return false; }
/** * path_basename: * @path : path * * Get basename from @path. * * Returns: basename from path. **/ const char *path_basename(const char *path) { /* We cut either at the first compression-related hash * or the last slash; whichever comes last */ const char *last = find_last_slash(path); const char *delim = path_get_archive_delim(path); if (delim) return delim + 1; if (last) return last + 1; return path; }
static int file_archive_extract_cb(const char *name, const char *valid_exts, const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size, uint32_t checksum, struct archive_extract_userdata *userdata) { const char *ext = path_get_extension(name); /* Extract first file that matches our list. */ if (ext && string_list_find_elem(userdata->ext, ext)) { char new_path[PATH_MAX_LENGTH]; char wanted_file[PATH_MAX_LENGTH]; const char *delim = NULL; new_path[0] = wanted_file[0] = '\0'; if (userdata->extraction_directory) fill_pathname_join(new_path, userdata->extraction_directory, path_basename(name), sizeof(new_path)); else fill_pathname_resolve_relative(new_path, userdata->archive_path, path_basename(name), sizeof(new_path)); userdata->first_extracted_file_path = strdup(new_path); delim = path_get_archive_delim(userdata->archive_path); if (delim) { strlcpy(wanted_file, delim + 1, sizeof(wanted_file)); if (!string_is_equal_noncase(userdata->extracted_file_path, wanted_file)) return 1; /* keep searching for the right file */ } else strlcpy(wanted_file, userdata->archive_path, sizeof(wanted_file)); if (file_archive_perform_mode(new_path, valid_exts, cdata, cmode, csize, size, 0, userdata)) userdata->found_file = true; return 0; } return 1; }
/** * path_basedir: * @path : path * * Extracts base directory by mutating path. * Keeps trailing '/'. **/ void path_basedir_wrapper(char *path) { char *last = NULL; if (strlen(path) < 2) return; #ifdef HAVE_COMPRESSION /* We want to find the directory with the archive in basedir. */ last = (char*)path_get_archive_delim(path); if (last) *last = '\0'; #endif last = find_last_slash(path); if (last) last[1] = '\0'; else snprintf(path, 3, ".%s", path_default_slash()); }
bool core_info_unsupported_content_path(const char *path) { size_t i; const char *archive_path = NULL; const char *delim = path_get_archive_delim(path); if (delim) archive_path = delim - 1; if (!core_info_curr_list) return false; /* if the path contains a compressed file and the core supports archives, * we don't want to look at this file */ if (archive_path) { for (i = 0; i < core_info_curr_list->count; i++) { const core_info_t *info = &core_info_curr_list->list[i]; if ( !string_list_find_elem(info->supported_extensions_list, "zip") && !string_list_find_elem(info->supported_extensions_list, "7z")) continue; return false; } } for (i = 0; i < core_info_curr_list->count; i++) { const core_info_t *info = &core_info_curr_list->list[i]; if (string_list_find_elem(info->supported_extensions_list, path_get_extension(path))) return false; } return true; }
/** * path_contains_compressed_file: * @path : path * * Checks if path contains a compressed file. * * Currently we only check for a hash symbol (#) inside the pathname * that is preceded by an archive extension. If path is ever expanded * to a general URI, we should check for that here. * * Example: Somewhere in the path there might be a compressed file * E.g.: /path/to/file.7z#mygame.img * * Returns: true (1) if path contains compressed file, otherwise false (0). **/ bool path_contains_compressed_file(const char *path) { return path_get_archive_delim(path) != NULL; }
/** * file_archive_get_file_crc32: * @path : filename path of archive * * Returns: CRC32 of the specified file in the archive, otherwise 0. * If no path within the archive is specified, the first * file found inside is used. **/ uint32_t file_archive_get_file_crc32(const char *path) { file_archive_transfer_t state; const struct file_archive_file_backend *backend = file_archive_get_file_backend(path); struct archive_extract_userdata userdata = {{0}}; bool returnerr = false; bool contains_compressed = false; const char *archive_path = NULL; if (!backend) return 0; contains_compressed = path_contains_compressed_file(path); if (contains_compressed) { archive_path = path_get_archive_delim(path); /* move pointer right after the delimiter to give us the path */ if (archive_path) archive_path += 1; } state.type = ARCHIVE_TRANSFER_INIT; state.archive_size = 0; state.handle = NULL; state.stream = NULL; state.footer = NULL; state.directory = NULL; state.data = NULL; state.backend = NULL; /* Initialize and open archive first. Sets next state type to ITERATE. */ file_archive_parse_file_iterate(&state, &returnerr, path, NULL, NULL, &userdata); for (;;) { /* Now find the first file in the archive. */ if (state.type == ARCHIVE_TRANSFER_ITERATE) file_archive_parse_file_iterate(&state, &returnerr, path, NULL, NULL, &userdata); /* If no path specified within archive, stop after * finding the first file. */ if (!contains_compressed) break; /* Stop when the right file in the archive is found. */ if (archive_path) { if (string_is_equal(userdata.extracted_file_path, archive_path)) break; } else break; } file_archive_parse_file_iterate_stop(&state); if (userdata.crc) return userdata.crc; return 0; }