/** * create_partitions * * Generate a list of PARTITION objects, which store the coordinates of blocks * in the matrix. These blocks can then be considered in the future - eg * for the purpose of choosing a list of EM starts from the matrix. The * array of partitions objects is referenced by the sp_matrix. * */ static void create_partitions ( SP_MATRIX *sp_mat ///< The sp_matrix object ///< Currently no parameters. May allow user manipulation later. ) { /* For every central s_point (ie s_point with central w and n) in the * matrix, calculate the boundaries of the current partition and then * generate a partition that fits within those bounds... */ int *central_widths = get_central_ws(sp_mat); int *central_nsites = get_central_ns(sp_mat); int w_idx; int n_partitions = 0; PARTITION **part_array = NULL; for (w_idx = 0; w_idx < get_num_central_widths(sp_mat); w_idx++) { int n_idx; for (n_idx = 0; n_idx < get_num_central_nsites(sp_mat); n_idx++) { int curr_w = central_widths[w_idx]; int curr_n = central_nsites[n_idx]; /* Calculate the boundaries within which the current partition must * be located. The boundaries are half way between the current * value and the adjacent value, unless there is no adjacent value * (in which case the boundary IS the current value): */ double min_w_bounds, max_w_bounds, min_n_bounds, max_n_bounds; if (curr_w == get_min_width(sp_mat)) { min_w_bounds = curr_w; } else { int prev_w = central_widths[w_idx - 1]; min_w_bounds = (curr_w + prev_w)/(double)2; } if (curr_w == get_max_width(sp_mat)) { max_w_bounds = curr_w; } else { int next_w = central_widths[w_idx + 1]; max_w_bounds = (curr_w + next_w)/(double)2; } if (curr_n == get_min_nsites(sp_mat)) { min_n_bounds = curr_n; } else { int prev_n = central_nsites[n_idx - 1]; min_n_bounds = (curr_n + prev_n)/(double)2; } if (curr_n == get_max_nsites(sp_mat)) { max_n_bounds = curr_n; } else { int next_n = central_nsites[n_idx + 1]; max_n_bounds = (curr_n + next_n)/(double)2; } /* Calculate the minimum and maximum w and n values which define the current partition. The minimum value is the smallest integer that is >= the minimum boundary. The maximum value is the largest integer that is < the maximum boundary, unless the maximum boundary is the max value in the sp_matrix (in which case the maximum value is the maximum boundary itself). This ensures that every s_point in the matrix will be assigned to a partition. */ int part_min_w, part_max_w, part_min_n, part_max_n; part_min_w = (int)ceil(min_w_bounds); part_min_n = (int)ceil(min_n_bounds); if (curr_w == get_max_width(sp_mat)) { part_max_w = curr_w; } else { // Largest integer LESS than max bounds: if (max_w_bounds == ceil(max_w_bounds)) { part_max_w = (int)max_w_bounds - 1; } else { part_max_w = (int)floor(max_w_bounds); } } if (curr_n == get_max_nsites(sp_mat)) { part_max_n = curr_n; } else { // Largest integer LESS than max bounds: if (max_n_bounds == ceil(max_n_bounds)) { part_max_n = (int)max_n_bounds - 1; } else { part_max_n = (int)floor(max_n_bounds); } } // Generate the current partition and add it to the growing array: PARTITION *curr_part = new_partition(part_min_w, part_max_w, curr_w, part_min_n, part_max_n, curr_n); (n_partitions)++; Resize(part_array, n_partitions, PARTITION *); part_array[(n_partitions) - 1] = curr_part; } // n_idx } // w_idx assert(sp_mat->partitions == NULL); sp_mat->partitions = part_array; sp_mat->n_parts = n_partitions; } // create_partitions
int main(int argc, char *argv[]) try { State state; auto parsers = new_subparser({"device"}); argp argp = {options, init_parsers, nullptr, doc, parsers.get(), nullptr, nullptr}; argp_parse(&argp, argc, argv, 0, nullptr, &state); Params params; try { params.load(state.device); } catch(const std::exception& e) { std::cerr << "Error: Header corrupt." << std::endl; return 1; } std::uint64_t blocks = state.device.size()/params.block_size; if (blocks <= 1) { std::cerr << "Error: No room for any partitions." << std::endl; return 1; } std::vector<bool> allocated_blocks(blocks); allocated_blocks[0] = true; std::string passphrase; Pinentry pinentry; pinentry.SETDESC("Enter passphrases for all partitions on this volume. " "Enter an empty passphrase after last passphrase."); pinentry.SETPROMPT("Passphrase:"); while ((passphrase = pinentry.GETPIN()) != "") { Superblock superblock(params, passphrase, blocks); try { superblock.load(state.device); for (auto block : superblock.blocks) allocated_blocks[block] = true; } catch(...) { pinentry.SETERROR("No partition found for that passphrase."); } } std::size_t free_blocks = 0; for (bool allocated : allocated_blocks) if (!allocated) free_blocks++; std::cout << free_blocks << " blocks free." << std::endl; if (free_blocks == 0) { std::cout << "Error: not enough free space." << std::endl; return 1; } if (state.blocks == 0) state.blocks = free_blocks; if (state.partition_size == 0) { decltype(state.partition_size) last; state.partition_size = state.blocks; do { last = state.partition_size; state.partition_size = state.blocks-Superblock::size_in_blocks(params, state.partition_size); } while (last != state.partition_size); } std::uint64_t blocks_required = state.partition_size+ Superblock::size_in_blocks(params, state.partition_size); state.blocks = std::min(state.blocks, blocks_required); if (state.blocks > free_blocks) { std::cerr << "Error: not enough free space." << std::endl; return 1; } pinentry.SETDESC("Enter passphrase for the new partition."); Superblock new_partition(params, pinentry.GETPIN(), blocks); if (allocated_blocks[new_partition.blocks.front()]) { std::cerr << "Error: superblock location already in use." << std::endl; return 1; } allocated_blocks[new_partition.blocks.front()] = true; state.blocks--; std::vector<std::uint64_t> pool; pool.reserve(free_blocks-1); for (std::size_t i = 0; i < blocks; i++) if (!allocated_blocks[i]) pool.push_back(i); std::shuffle(pool.begin(), pool.end(), std::random_device()); for (; state.blocks > 0; state.blocks--, state.partition_size--) { new_partition.blocks.push_back(pool.back()); pool.pop_back(); } for (; state.partition_size > 0; state.partition_size--) new_partition.blocks.push_back(0); new_partition.store(state.device); return 0; } catch(const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; return 1; }