#include "reader.h" #include #include #include #include #include #include #include struct ropkg_package { fx_file *pkg_file; fx_cstream *pkg_file_cstream; struct ropkg_reader *pkg_reader; fx_directory *pkg_metadata; }; static fx_result extract_file( struct ropkg_reader *pkg, const char *path_cstr, fx_directory *dest) { fx_path *path = fx_path_create_from_cstr(path_cstr); if (!path) { return ROPKG_RESULT_ERR(NO_MEMORY); } fx_path *dir_path = NULL; fx_path_get_directory(path, &dir_path); if (!dir_path) { fx_path_unref(path); return ROPKG_RESULT_ERR(NO_MEMORY); } fx_result result = FX_RESULT_SUCCESS; if (fx_path_length(dir_path) > 0) { fx_directory *parent_dir; result = fx_directory_open( dest, dir_path, FX_DIRECTORY_OPEN_CREATE_INTERMEDIATE, &parent_dir); fx_directory_unref(parent_dir); } if (fx_result_is_error(result)) { goto end; } fx_file *dest_file = NULL; result = fx_file_open( dest, path, FX_FILE_WRITE_ONLY | FX_FILE_CREATE | FX_FILE_BINARY, &dest_file); if (fx_result_is_error(result)) { goto end; } char data[] = "Hello"; size_t nr_written = 0; fx_file_write(dest_file, 0, sizeof data, data, &nr_written); fx_file_unref(dest_file); end: fx_path_unref(path); fx_path_unref(dir_path); return result; } static fx_result extract_subpackage( struct ropkg_reader *pkg, const char *name, fx_directory *dest) { fx_directory *dest_subdir; fx_result result = fx_directory_open( dest, FX_RV_PATH(name), FX_DIRECTORY_OPEN_CREATE, &dest_subdir); if (fx_result_is_error(result)) { return result; } fx_cstream_begin_compressed_section(pkg->r_stream, NULL); struct ropkg_reader *subpkg = NULL; enum ropkg_status status = ropkg_reader_open(pkg->r_stream, &subpkg); if (status != ROPKG_SUCCESS) { result = ROPKG_RESULT_STATUS(status); goto end; } while (!ropkg_reader_eof(subpkg)) { const struct ropkg_file_info *file = ropkg_reader_current_file(subpkg); result = extract_file(subpkg, file->f_filename, dest_subdir); if (fx_result_is_error(result)) { break; } status = ropkg_reader_move_next(subpkg); if (status != ROPKG_SUCCESS) { result = ROPKG_RESULT_STATUS(status); break; } } end: fx_cstream_end_compressed_section(pkg->r_stream, NULL, NULL); return result; } static fx_result extract_metadata(struct ropkg_reader *pkg, fx_directory *dest) { fx_result result = FX_RESULT_SUCCESS; while (!ropkg_reader_eof(pkg)) { const struct ropkg_file_info *file = ropkg_reader_current_file(pkg); int section = -1; if (!strncmp(file->f_filename, "meta.tar", 8)) { result = extract_subpackage(pkg, "meta", dest); } else if (!strncmp(file->f_filename, "control.tar", 11)) { result = extract_subpackage(pkg, "control", dest); } if (fx_result_is_error(result)) { break; } enum ropkg_status status = ropkg_reader_move_next(pkg); if (status != ROPKG_SUCCESS) { result = ROPKG_RESULT_STATUS(status); break; } } return result; } fx_result ropkg_package_open( fx_directory *dir, const char *path, struct ropkg_package **out) { struct ropkg_package *pkg = malloc(sizeof *pkg); if (!pkg) { return ROPKG_RESULT_ERR(NO_MEMORY); } memset(pkg, 0x0, sizeof *pkg); fx_result result = fx_file_open( dir, FX_RV_PATH(path), FX_FILE_READ_ONLY | FX_FILE_BINARY, &pkg->pkg_file); if (fx_result_is_error(result)) { ropkg_package_close(pkg); return fx_result_propagate(result); } fx_status bstatus = fx_cstream_open( pkg->pkg_file, FX_TYPE_ZSTD_COMPRESSOR, FX_COMPRESSOR_MODE_DECOMPRESS, &pkg->pkg_file_cstream); if (!FX_OK(bstatus)) { ropkg_package_close(pkg); return FX_RESULT_STATUS(bstatus); } enum ropkg_status status = ropkg_reader_open(pkg->pkg_file_cstream, &pkg->pkg_reader); if (status != ROPKG_SUCCESS) { ropkg_package_close(pkg); return ROPKG_RESULT_STATUS(status); } result = fx_directory_open_temp(&pkg->pkg_metadata); if (fx_result_is_error(result)) { ropkg_package_close(pkg); return fx_result_propagate(result); } result = extract_metadata(pkg->pkg_reader, pkg->pkg_metadata); if (fx_result_is_error(result)) { ropkg_package_close(pkg); return fx_result_propagate(result); } *out = pkg; return ROPKG_RESULT_SUCCESS; } fx_result ropkg_package_close(struct ropkg_package *pkg) { if (pkg->pkg_reader) { ropkg_reader_close(pkg->pkg_reader); pkg->pkg_reader = NULL; } if (pkg->pkg_file_cstream) { fx_cstream_unref(pkg->pkg_file_cstream); pkg->pkg_file_cstream = NULL; } if (pkg->pkg_file) { fx_file_unref(pkg->pkg_file); pkg->pkg_file = NULL; } if (pkg->pkg_metadata) { fx_directory_unref(pkg->pkg_metadata); pkg->pkg_metadata = NULL; } free(pkg); return FX_RESULT_SUCCESS; }