Esempio n. 1
0
	/**
	 * Standard Constructor. a is the array to be prepared for RMQ.
	 * n is the size of the array.
	 * */
	RMQ_succinct::RMQ_succinct(int* a, unsigned int n) {
		this->a = a;
		this->n = n;
		s = 1 << 3;				 // microblock-size
		sprime = 1 << 4;		 // block-size
		sprimeprime = 1 << 8;	 // superblock-size
		nb = block(n-1)+1;		 // number of blocks
		nsb = superblock(n-1)+1; // number of superblocks
		nmb = microblock(n-1)+1; // number of microblocks

		// The following is necessary because we've fixed s, s' and s'' according to the computer's
		// word size and NOT according to the input size. This may cause the (super-)block-size
		// to be too big, or, in other words, the array too small. If this code is compiled on
		// a 32-bit computer, this happens iff n < 113. For such small instances it isn't
		// advisable anyway to use this data structure, because simpler methods are faster and
		// less space consuming.
		if (nb<sprimeprime/(2*sprime)) { cerr << "Array too small...exit\n"; exit(-1); }
		// Type-calculation for the microblocks and pre-computation of in-microblock-queries:
		type = new DTsucc2[nmb];
		Prec = new DTsucc*[Catalan[s][s]];
		for (unsigned int i = 0; i < Catalan[s][s]; i++) {
			Prec[i] = new DTsucc[s];
			for(unsigned int j=0; j<s;j++)
				Prec[i][j]=0;
			Prec[i][0] = 1;		 // init with impossible value
		}

		int* rp = new int[s+1];	 // rp: rightmost path in Cart. tree
		unsigned int z = 0;		 // index in array a
		unsigned int start;		 // start of current block
		unsigned int end;		 // end of current block
		unsigned int q;			 // position in Catalan triangle
		unsigned int p;			 // --------- " ----------------
		rp[0] = minus_infinity;	 // stopper (minus infinity)

		// prec[i]: the jth bit is 1 iff j is 1. pos. to the left of i where a[j] < a[i]
		unsigned int* gstack = new unsigned int[s];
		unsigned int gstacksize;
		unsigned int g;			 // first position to the left of i where a[g[i]] < a[i]

								 // step through microblocks
		for (unsigned int i = 0; i < nmb; i++) {
			start = z;			 // init start
			end = start + s;	 // end of block (not inclusive!)
			if (end > n) end = n;// last block could be smaller than s!
			// compute block type as in Fischer/Heun CPM'06:
			q = s;				 // init q
			p = s-1;			 // init p
			type[i] = 0;		 // init type (will be increased!)
			rp[1] = a[z];		 // init rightmost path

			while (++z < end) {	 // step through current block:
				p--;
				while (rp[q-p-1] > a[z]) {
								 // update type
					type[i] += Catalan[p][q];
					q--;
				}
				rp[q-p] = a[z];	 // add last element to rightmost path
			}

			// precompute in-block-queries for this microblock (if necessary)
			// as in Alstrup et al. SPAA'02:
			if (Prec[type[i]][0] == 1) {
				Prec[type[i]][0] = 0;
				gstacksize = 0;
				for (unsigned int j = start; j < end; j++) {
					while(gstacksize > 0 && (a[j] < a[gstack[gstacksize-1]])) {
						gstacksize--;
					}
					if(gstacksize > 0) {
						g = gstack[gstacksize-1];
						Prec[type[i]][j-start] = Prec[type[i]][g-start] | (1 << (g % s));
					}
					else Prec[type[i]][j-start] = 0;
					gstack[gstacksize++] = j;
				}
			}
		}
		delete[] rp;
		delete[] gstack;

		// space for out-of-block- and out-of-superblock-queries:
		M_depth = (unsigned int) floor(log2(((double) sprimeprime / (double) sprime)));
		M = new DTsucc*[M_depth];
		M[0] = new DTsucc[nb];
		Mprime_depth = (unsigned int) floor(log2(nsb)) + 1;
		Mprime = new unsigned int*[Mprime_depth];
		Mprime[0] = new unsigned int[nsb];

		// fill 0'th rows of M and Mprime:
		z = 0;					 // minimum in current block
		q = 0;					 // pos. of min in current superblock
		g = 0;					 // number of current superblock
								 // step through blocks
		for (unsigned int i = 0; i < nb; i++) {
			start = z;			 // init start
			p = start;			 // init minimum
			end = start + sprime;// end of block (not inclusive!)
			if (end > n) end = n;// last block could be smaller than sprime!
								 // update minimum in superblock
			if (a[z] < a[q]) q = z;

			while (++z < end) {	 // step through current block:
								 // update minimum in block
				if (a[z] < a[p]) p = z;
								 // update minimum in superblock
				if (a[z] < a[q]) q = z;
			}
			M[0][i] = p-start;	 // store index of block-minimum (offset!)
								 // reached end of superblock?
			if (z % sprimeprime == 0 || z == n) {
								 // store index of superblock-minimum
				Mprime[0][g++] = q;
				q = z;
			}
		}

		// fill M
		unsigned int dist = 1;	 // always 2^(j-1)
		for (unsigned int j = 1; j < M_depth; j++) {
			M[j] = new DTsucc[nb];
								 // be careful: loop may go too far
			for (unsigned int i = 0; i < nb - dist; i++) {
				M[j][i] = a[m(j-1, i)] <= a[m(j-1,i+dist)] ?
								 // add 'skipped' elements in a
					M[j-1][i] : M[j-1][i+dist] + (dist*sprime);
			}
								 // fill overhang
			for (unsigned int i = nb - dist; i < nb; i++) M[j][i] = M[j-1][i];
			dist *= 2;
		}

		// fill M':
		dist = 1;				 // always 2^(j-1)
		for (unsigned int j = 1; j < Mprime_depth; j++) {
			Mprime[j] = new unsigned int[nsb];
			for (unsigned int i = 0; i < nsb - dist; i++) {
				Mprime[j][i] = a[Mprime[j-1][i]] <= a[Mprime[j-1][i+dist]] ?
					Mprime[j-1][i] : Mprime[j-1][i+dist];
			}
								 // overhang
			for (unsigned int i = nsb - dist; i < nsb; i++) Mprime[j][i] = Mprime[j-1][i];
			dist *= 2;
		}
	}
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;

    Pinentry pinentry;
    pinentry.SETDESC("Enter passphrases for a partition on this volume.");
    pinentry.SETPROMPT("Passphrase:");
    auto passphrase = pinentry.GETPIN();
    Superblock superblock(params, passphrase, blocks);
    try {
      superblock.load(state.device);
    } catch(...) {
      std::cerr << "Error: No partition found for that passphrase." << std::endl;
    }
    Hash hash(params.hash);
    std::string key = PBKDF2::PBKDF2(hash, passphrase, params.salt,
        params.iters, params.key_size);

    if (state.name.empty()) {
      hash.reset();
      hash.update(key);
      state.name = hex(hash.digest()).substr(8);
    }

    {
      std::unique_ptr<dm_task, void(*)(dm_task*)> dmt(
          dm_task_create(DM_DEVICE_CREATE), dm_task_destroy);
      if (!dmt.get())
        throw std::runtime_error("dm_task_create failed");
      if (!dm_task_set_name(dmt.get(), state.name.c_str()))
        throw std::runtime_error("dm_task_set_name failed");
      std::uint64_t offset = 0;
      for (auto block = superblock.blocks.begin()+superblock.offset;
          block != superblock.blocks.end();
          block++, offset += params.block_size) {
        if (*block != 0) {
          std::stringstream ss;
          ss << params.device_cipher << " " << hex(key) << " 0 ";
          ss << state.device.major() << ":" << state.device.minor() << " ";
          ss << (*block)*params.block_size/512;
          if (!dm_task_add_target(dmt.get(), offset/512, params.block_size/512,
                "crypt", ss.str().c_str()))
            throw std::runtime_error("dm_task_add_target(\"crypt\") failed");
        } else {
          if (!dm_task_add_target(dmt.get(), offset/512, params.block_size/512,
                "error", ""))
            throw std::runtime_error("dm_task_add_target(\"error\") failed");
        }
      }
      if (!dm_task_run(dmt.get()))
        throw std::runtime_error("dm_task_run failed");
    }

    return 0;
  } catch(const std::exception& e) {
    std::cerr << "Error: " << e.what() << std::endl;
    return 1;
  }
Esempio n. 3
0
	unsigned int RMQ_succinct::query(unsigned int i, unsigned int j) {
								 // i's microblock
		unsigned int mb_i = microblock(i);
								 // j's microblock
		unsigned int mb_j = microblock(j);
								 // min: to be returned
		unsigned int min, min_i, min_j;
								 // start of i's microblock
		unsigned int s_mi = mb_i * s;
								 // pos. of i in its microblock
		unsigned int i_pos = i - s_mi;

		if (mb_i == mb_j) {		 // only one microblock-query
			min_i = clearbits(Prec[type[mb_i]][j-s_mi], i_pos);
			min = min_i == 0 ? j : s_mi + lsb(min_i);
		}
		else {
								 // i's block
			unsigned int b_i = block(i);
								 // j's block
			unsigned int b_j = block(j);
								 // start of j's microblock
			unsigned int s_mj = mb_j * s;
								 // position of j in its microblock
			unsigned int j_pos = j - s_mj;
			min_i = clearbits(Prec[type[mb_i]][s-1], i_pos);
								 // left in-microblock-query
			min = min_i == 0 ? s_mi + s - 1 : s_mi + lsb(min_i);
			min_j = Prec[type[mb_j]][j_pos] == 0 ?
								 // right in-microblock-query
				j : s_mj + lsb(Prec[type[mb_j]][j_pos]);
			if (a[min_j] < a[min]) min = min_j;

								 // otherwise we're done!
			if (mb_j > mb_i + 1) {
								 // start of block i
				unsigned int s_bi = b_i * sprime;
								 // start of block j
				unsigned int s_bj = b_j * sprime;
								 // do another microblock-query!
				if (s_bi+s > i) {
					mb_i++;		 // go one microblock to the right
					min_i = Prec[type[mb_i]][s-1] == 0 ?
								 // right in-block-query
						s_bi + sprime - 1 : s_mi + s + lsb(Prec[type[mb_i]][s-1]);
					if (a[min_i] < a[min]) min = min_i;
				}
								 // and yet another microblock-query!
				if (j >= s_bj+s) {
					mb_j--;		 // go one microblock to the left
					min_j = Prec[type[mb_j]][s-1] == 0 ?
								 // right in-block-query
						s_mj - 1 : s_bj + lsb(Prec[type[mb_j]][s-1]);
					if (a[min_j] < a[min]) min = min_j;
				}

				unsigned int block_difference = b_j - b_i;
								 // otherwise we're done!
				if (block_difference > 1) {
								 // for index calculations in M and M'
					unsigned int k, twotothek, block_tmp;
					b_i++;		 // block where out-of-block-query starts
								 // just one out-of-block-query
					if (s_bj - s_bi - sprime <= sprimeprime) {
						k = log2fast(block_difference - 2);
								 // 2^k
						twotothek = 1 << k;
						i = m(k, b_i); j = m(k, b_j-twotothek);
						min_i = a[i] <= a[j] ? i : j;
					}
					else {		 // here we have to answer a superblock-query:
								 // i's superblock
						unsigned int sb_i = superblock(i);
								 // j's superblock
						unsigned int sb_j = superblock(j);

								 // end of left out-of-block-query
						block_tmp = block((sb_i+1)*sprimeprime);
						k = log2fast(block_tmp - b_i);
								 // 2^k
						twotothek = 1 << k;
						i = m(k, b_i); j = m(k, block_tmp+1-twotothek);
						min_i = a[i] <= a[j] ? i : j;

								 // start of right out-of-block-query
						block_tmp = block(sb_j*sprimeprime);
						k = log2fast(b_j - block_tmp);
								 // 2^k
						twotothek = 1 << k;
								 // going one block to the left doesn't harm and saves some tests
						block_tmp--;
						i = m(k, block_tmp); j = m(k, b_j-twotothek);
						min_j = a[i] <= a[j] ? i : j;

						if (a[min_j] < a[min_i]) min_i = min_j;

								 // finally, the superblock-query:
						if (sb_j > sb_i + 1) {
							k = log2fast(sb_j - sb_i - 2);
							twotothek = 1 << k;
							i = Mprime[k][sb_i+1]; j = Mprime[k][sb_j-twotothek];
							min_j = a[i] <= a[j] ? i : j;
								 // does NOT always return leftmost min!!!
							if (a[min_j] < a[min_i]) min_i = min_j;
						}
					}
								 // does NOT always return leftmost min!!!
					if (a[min_i] < a[min]) min = min_i;
				}
			}
		}
		return min;
	}
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;
  }