Esempio n. 1
0
settings_pack load_pack_from_dict(bdecode_node const& settings)
{
    settings_pack pack;

    for (int i = 0; i < settings.dict_size(); ++i)
    {
        string_view key;
        bdecode_node val;
        std::tie(key, val) = settings.dict_at(i);
        switch (val.type())
        {
        case bdecode_node::dict_t:
        case bdecode_node::list_t:
            continue;
        case bdecode_node::int_t:
        {
            bool found = false;
            for (int k = 0; k < sizeof(int_settings) / sizeof(int_settings[0]); ++k)
            {
                if (key != int_settings[k].name) continue;
                pack.set_int(settings_pack::int_type_base + k, val.int_value());
                found = true;
                break;
            }
            if (found) continue;
            for (int k = 0; k < sizeof(bool_settings) / sizeof(bool_settings[0]); ++k)
            {
                if (key != bool_settings[k].name) continue;
                pack.set_bool(settings_pack::bool_type_base + k, val.int_value() != 0);
                break;
            }
        }
        break;
        case bdecode_node::string_t:
            for (int k = 0; k < sizeof(str_settings) / sizeof(str_settings[0]); ++k)
            {
                if (key != str_settings[k].name) continue;
                pack.set_str(settings_pack::string_type_base + k, val.string_value().to_string());
                break;
            }
            break;
        case bdecode_node::none_t:
            break;
        }
    }
    return pack;
}
Esempio n. 2
0
	// convert a bdecode_node into an old skool entry
	void entry::operator=(bdecode_node const& e)
	{
		switch (e.type())
		{
			case bdecode_node::string_t:
				this->string() = e.string_value();
				break;
			case bdecode_node::int_t:
				this->integer() = e.int_value();
				break;
			case bdecode_node::dict_t:
			{
				dictionary_type& d = this->dict();
				for (int i = 0; i < e.dict_size(); ++i)
				{
					std::pair<std::string, bdecode_node> elem = e.dict_at(i);
					d[elem.first] = elem.second;
				}
				break;
			}
			case bdecode_node::list_t:
			{
				list_type& l = this->list();
				for (int i = 0; i < e.list_size(); ++i)
				{
					l.push_back(entry());
					l.back() = e.list_at(i);
				}
				break;
			}
			case bdecode_node::none_t:
				destruct();
				break;
		}
	}
Esempio n. 3
0
bool item::assign(bdecode_node const& v, span<char const> salt
	, sequence_number const seq, public_key const& pk, signature const& sig)
{
	TORRENT_ASSERT(v.data_section().size() <= 1000);
	if (!verify_mutable_item(v.data_section(), salt, seq, pk, sig))
		return false;
	m_pk = pk;
	m_sig = sig;
	if (salt.size() > 0)
		m_salt.assign(salt.data(), salt.size());
	else
		m_salt.clear();
	m_seq = seq;
	m_mutable = true;

	m_value = v;
	return true;
}
Esempio n. 4
0
void render_variant(std::string& out, bdecode_node const& e)
{
	switch (e.type())
	{
		case bdecode_node::dict_t:
			print_dict(out);
			for (int i = 0; i < e.dict_size(); ++i)
			{
				std::pair<lt::string_view, bdecode_node> item = e.dict_at(i);
				const bool duplicate = g_seed == 1;
				const bool skipped = g_seed == 2;
				g_seed -= 2;
				if (duplicate)
				{
					print_string(out, item.first.to_string());
					render_variant(out, item.second);
				}
				if (!skipped)
				{
					print_string(out, item.first.to_string());
					render_variant(out, item.second);
				}

				render_arbitrary_item(out);
			}
			print_terminate(out);
			break;
		case bdecode_node::list_t:
			print_list(out);
			for (int i = 0; i < e.list_size(); ++i)
			{
				const bool duplicate = g_seed == 1;
				const bool skipped = g_seed == 2;
				g_seed -= 2;
				if (duplicate) render_variant(out, e.list_at(i));

				render_arbitrary_item(out);

				if (!skipped) render_variant(out, e.list_at(i));
			}
			print_terminate(out);
			break;
		case bdecode_node::int_t:
			print_int(out, e.int_value());
			break;
		case bdecode_node::string_t:
			print_string(out, e.string_value().to_string());
			break;
		default:
			abort();
	}
}
	// root_dir is the name of the torrent, unless this is a single file
	// torrent, in which case it's empty.
	bool extract_files(bdecode_node const& list, file_storage& target
		, std::string const& root_dir, ptrdiff_t info_ptr_diff, error_code& ec)
	{
		if (list.type() != bdecode_node::list_t)
		{
			ec = errors::torrent_file_parse_failed;
			return false;
		}
		target.reserve(list.list_size());

		// this is the counter used to name pad files
		int pad_file_cnt = 0;
		for (int i = 0, end(list.list_size()); i < end; ++i)
		{
			if (!extract_single_file(list.list_at(i), target, root_dir
				, info_ptr_diff, false, pad_file_cnt, ec))
				return false;
		}
		return true;
	}
Esempio n. 6
0
void get_item::got_data(bdecode_node const& v,
	public_key const& pk,
	sequence_number const seq,
	signature const& sig)
{
	// we received data!
	// if no data_callback, we needn't care about the data we get.
	// only put_immutable_item no data_callback
	if (!m_data_callback) return;

	// for get_immutable_item
	if (m_immutable)
	{
		// If m_data isn't empty, we should have post alert.
		if (!m_data.empty()) return;

		sha1_hash incoming_target = item_target_id(v.data_section());
		if (incoming_target != target()) return;

		m_data.assign(v);

		// There can only be one true immutable item with a given id
		// Now that we've got it and the user doesn't want to do a put
		// there's no point in continuing to query other nodes
		m_data_callback(m_data, true);
		done();

		return;
	}

	// immutable data should have been handled before this line, only mutable
	// data can reach here, which means pk, sig and seq must be valid.

	std::string const salt_copy(m_data.salt());
	sha1_hash const incoming_target = item_target_id(salt_copy, pk);
	if (incoming_target != target()) return;

	// this is mutable data. If it passes the signature
	// check, remember it. Just keep the version with
	// the highest sequence number.
	if (m_data.empty() || m_data.seq() < seq)
	{
		if (!m_data.assign(v, salt_copy, seq, pk, sig))
			return;

		// for get_item, we should call callback when we get data,
		// even if the date is not authoritative, we can update later.
		// so caller can get response ASAP without waiting transaction
		// time-out (15 seconds).
		// for put_item, the callback function will do nothing
		// if the data is non-authoritative.
		m_data_callback(m_data, false);
	}
}
// TODO: 2 returning a bool here is redundant. Instead this function should
// return the peer_entry
bool extract_peer_info(bdecode_node const& info, peer_entry& ret, error_code& ec)
{
    // extract peer id (if any)
    if (info.type() != bdecode_node::dict_t)
    {
        ec.assign(errors::invalid_peer_dict, get_libtorrent_category());
        return false;
    }
    bdecode_node i = info.dict_find_string("peer id");
    if (i && i.string_length() == 20)
    {
        std::copy(i.string_ptr(), i.string_ptr()+20, ret.pid.begin());
    }
    else
    {
        // if there's no peer_id, just initialize it to a bunch of zeroes
        std::fill_n(ret.pid.begin(), 20, 0);
    }

    // extract ip
    i = info.dict_find_string("ip");
    if (i == 0)
    {
        ec.assign(errors::invalid_tracker_response, get_libtorrent_category());
        return false;
    }
    ret.hostname = i.string_value();

    // extract port
    i = info.dict_find_int("port");
    if (i == 0)
    {
        ec.assign(errors::invalid_tracker_response, get_libtorrent_category());
        return false;
    }
    ret.port = boost::uint16_t(i.int_value());

    return true;
}
Esempio n. 8
0
	void on_read(lt::error_code const& ec, std::size_t bytes_transferred)
	{
		if (ec) return;

		using libtorrent::entry;
		using libtorrent::bdecode;

		int pos;
		error_code err;

		// since the simulation is single threaded, we can get away with just
		// allocating a single of these
		static bdecode_node msg;
		int ret = bdecode(m_buffer, m_buffer + bytes_transferred, msg, err, &pos, 10, 500);
		if (ret != 0) return;

		if (msg.type() != bdecode_node::dict_t) return;

		libtorrent::dht::msg m(msg, m_ep);
		dht().incoming(m);

		sock().async_receive_from(asio::mutable_buffers_1(m_buffer, sizeof(m_buffer))
			, m_ep, boost::bind(&dht_node::on_read, this, _1, _2));
	}
Esempio n. 9
0
bool item::assign(bdecode_node const& v
                  , std::pair<char const*, int> salt
                  , boost::uint64_t seq, char const* pk, char const* sig)
{
    TORRENT_ASSERT(v.data_section().second <= 1000);
    if (pk && sig)
    {
        if (!verify_mutable_item(v.data_section(), salt, seq, pk, sig))
            return false;
        memcpy(m_pk.c_array(), pk, item_pk_len);
        memcpy(m_sig.c_array(), sig, item_sig_len);
        if (salt.second > 0)
            m_salt.assign(salt.first, salt.second);
        else
            m_salt.clear();
        m_seq = seq;
        m_mutable = true;
    }
    else
        m_mutable = false;

    m_value = v;
    return true;
}
Esempio n. 10
0
bool verify_message(bdecode_node const& message, key_desc_t const desc[]
	, bdecode_node ret[], int size, char* error, int error_size)
{
	// get a non-root bdecode_node that still
	// points to the root. message should not be copied
	bdecode_node msg = message.non_owning();

	// clear the return buffer
	for (int i = 0; i < size; ++i)
		ret[i].clear();

	// when parsing child nodes, this is the stack
	// of bdecode_nodes to return to
	bdecode_node stack[5];
	int stack_ptr = -1;

	if (msg.type() != bdecode_node::dict_t)
	{
		snprintf(error, error_size, "not a dictionary");
		return false;
	}
	++stack_ptr;
	stack[stack_ptr] = msg;
	for (int i = 0; i < size; ++i)
	{
		key_desc_t const& k = desc[i];

		//		fprintf(stderr, "looking for %s in %s\n", k.name, print_entry(*msg).c_str());

		ret[i] = msg.dict_find(k.name);
		// none_t means any type
		if (ret[i] && ret[i].type() != k.type && k.type != bdecode_node::none_t)
			ret[i].clear();
		if (ret[i] == 0 && (k.flags & key_desc_t::optional) == 0)
		{
			// the key was not found, and it's not an optional key
			snprintf(error, error_size, "missing '%s' key", k.name);
			return false;
		}

		if (k.size > 0
			&& ret[i]
			&& k.type == bdecode_node::string_t)
		{
			bool invalid = false;
			if (k.flags & key_desc_t::size_divisible)
				invalid = (ret[i].string_length() % k.size) != 0;
			else
				invalid = ret[i].string_length() != k.size;

			if (invalid)
			{
				// the string was not of the required size
				ret[i].clear();
				if ((k.flags & key_desc_t::optional) == 0)
				{
					snprintf(error, error_size, "invalid value for '%s'", k.name);
					return false;
				}
			}
		}
		if (k.flags & key_desc_t::parse_children)
		{
			TORRENT_ASSERT(k.type == bdecode_node::dict_t);

			if (ret[i])
			{
				++stack_ptr;
				TORRENT_ASSERT(stack_ptr < int(sizeof(stack) / sizeof(stack[0])));
				msg = ret[i];
				stack[stack_ptr] = msg;
			}
			else
			{
				// skip all children
				while (i < size && (desc[i].flags & key_desc_t::last_child) == 0) ++i;
				// if this assert is hit, desc is incorrect
				TORRENT_ASSERT(i < size);
			}
		}
		else if (k.flags & key_desc_t::last_child)
		{
			TORRENT_ASSERT(stack_ptr > 0);
			// this can happen if the specification passed
			// in is unbalanced. i.e. contain more last_child
			// nodes than parse_children
			if (stack_ptr == 0) return false;
			--stack_ptr;
			msg = stack[stack_ptr];
		}
	}
	return true;
}
Esempio n. 11
0
	int bdecode(char const* start, char const* end, bdecode_node& ret
		, error_code& ec, int* error_pos, int depth_limit, int token_limit)
	{
		ec.clear();
		ret.clear();

		if (end - start > bdecode_token::max_offset)
		{
			if (error_pos) *error_pos = 0;
			ec = make_error_code(bdecode_errors::limit_exceeded);
			return -1;
		}

		// this is the stack of bdecode_token indices, into m_tokens.
		// sp is the stack pointer, as index into the array, stack
		int sp = 0;
		stack_frame* stack = TORRENT_ALLOCA(stack_frame, depth_limit);

		char const* const orig_start = start;
		if (start == end) return 0;

		while (start <= end)
		{
			if (start >= end) TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);

			if (sp >= depth_limit)
				TORRENT_FAIL_BDECODE(bdecode_errors::depth_exceeded);

			--token_limit;
			if (token_limit < 0)
				TORRENT_FAIL_BDECODE(bdecode_errors::limit_exceeded);

			// look for a new token
			const char t = *start;

			const int current_frame = sp;

			// if we're currently parsing a dictionary, assert that
			// every other node is a string.
			if (current_frame > 0
				&& ret.m_tokens[stack[current_frame-1].token].type == bdecode_token::dict)
			{
				if (stack[current_frame-1].state == 0)
				{
					// the current parent is a dict and we are parsing a key.
					// only allow a digit (for a string) or 'e' to terminate
					if (!numeric(t) && t != 'e')
						TORRENT_FAIL_BDECODE(bdecode_errors::expected_digit);
				}
			}

			switch (t)
			{
				case 'd':
					stack[sp++] = ret.m_tokens.size();
					// we push it into the stack so that we know where to fill
					// in the next_node field once we pop this node off the stack.
					// i.e. get to the node following the dictionary in the buffer
					ret.m_tokens.push_back(bdecode_token(start - orig_start
						, bdecode_token::dict));
					++start;
					break;
				case 'l':
					stack[sp++] = ret.m_tokens.size();
					// we push it into the stack so that we know where to fill
					// in the next_node field once we pop this node off the stack.
					// i.e. get to the node following the list in the buffer
					ret.m_tokens.push_back(bdecode_token(start - orig_start
						, bdecode_token::list));
					++start;
					break;
				case 'i':
				{
					char const* int_start = start;
					bdecode_errors::error_code_enum e = bdecode_errors::no_error;
					// +1 here to point to the first digit, rather than 'i'
					start = check_integer(start + 1, end, e);
					if (e)
					{
						// in order to gracefully terminate the tree,
						// make sure the end of the previous token is set correctly
						if (error_pos) *error_pos = start - orig_start;
						error_pos = NULL;
						start = int_start;
						TORRENT_FAIL_BDECODE(e);
					}
					ret.m_tokens.push_back(bdecode_token(int_start - orig_start
						, 1, bdecode_token::integer, 1));
					TORRENT_ASSERT(*start == 'e');

					// skip 'e'
					++start;
					break;
				}
				case 'e':
				{
					// this is the end of a list or dict
					if (sp == 0)
						TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);

					if (sp > 0
						&& ret.m_tokens[stack[sp-1].token].type == bdecode_token::dict
						&& stack[sp-1].state == 1)
					{
						// this means we're parsing a dictionary and about to parse a
						// value associated with a key. Instad, we got a termination
						TORRENT_FAIL_BDECODE(bdecode_errors::expected_value);
					}

					// insert the end-of-sequence token
					ret.m_tokens.push_back(bdecode_token(start - orig_start, 1
						, bdecode_token::end));

					// and back-patch the start of this sequence with the offset
					// to the next token we'll insert
					int top = stack[sp-1].token;
					// subtract the token's own index, since this is a relative
					// offset
					if (ret.m_tokens.size() - top > bdecode_token::max_next_item)
						TORRENT_FAIL_BDECODE(bdecode_errors::limit_exceeded);

					ret.m_tokens[top].next_item = ret.m_tokens.size() - top;

					// and pop it from the stack.
					--sp;
					++start;
					break;
				}
				default:
				{
					// this is the case for strings. The start character is any
					// numeric digit
					if (!numeric(t))
						TORRENT_FAIL_BDECODE(bdecode_errors::expected_value);

					boost::int64_t len = t - '0';
					char const* str_start = start;
					++start;
					bdecode_errors::error_code_enum e = bdecode_errors::no_error;
					start = parse_int(start, end, ':', len, e);
					if (e)
						TORRENT_FAIL_BDECODE(e);

					// remaining buffer size excluding ':'
					const ptrdiff_t buff_size = end - start - 1;
					if (len > buff_size)
						TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);
					if (len < 0)
						TORRENT_FAIL_BDECODE(bdecode_errors::overflow);

					// skip ':'
					++start;
					if (start >= end) TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);

					// the bdecode_token only has 8 bits to keep the header size
					// in. If it overflows, fail!
					if (start - str_start - 2 > detail::bdecode_token::max_header)
						TORRENT_FAIL_BDECODE(bdecode_errors::limit_exceeded);

					ret.m_tokens.push_back(bdecode_token(str_start - orig_start
						, 1, bdecode_token::string, start - str_start));
					start += len;
					break;
				}
			}

			if (current_frame > 0
				&& ret.m_tokens[stack[current_frame-1].token].type == bdecode_token::dict)
			{
				// the next item we parse is the opposite
				stack[current_frame-1].state = ~stack[current_frame-1].state;
			}

			// this terminates the top level node, we're done!
			if (sp == 0) break;
		}

done:

		// if parse failed, sp will be greater than 1
		// unwind the stack by inserting terminator to make whatever we have
		// so far valid
		while (sp > 0) {
			TORRENT_ASSERT(ec);
			--sp;

			// we may need to insert a dummy token to properly terminate the tree,
			// in case we just parsed a key to a dict and failed in the value
			if (ret.m_tokens[stack[sp].token].type == bdecode_token::dict
				&& stack[sp].state == 1)
			{
				// insert an empty dictionary as the value
				ret.m_tokens.push_back(bdecode_token(start - orig_start
					, 2, bdecode_token::dict));
				ret.m_tokens.push_back(bdecode_token(start - orig_start
					, bdecode_token::end));
			}

			int top = stack[sp].token;
			TORRENT_ASSERT(ret.m_tokens.size() - top <= bdecode_token::max_next_item);
			ret.m_tokens[top].next_item = ret.m_tokens.size() - top;
			ret.m_tokens.push_back(bdecode_token(start - orig_start, 1, bdecode_token::end));
		}

		ret.m_tokens.push_back(bdecode_token(start - orig_start, 0
			, bdecode_token::end));

		ret.m_token_idx = 0;
		ret.m_buffer = orig_start;
		ret.m_buffer_size = start - orig_start;
		ret.m_root_tokens = &ret.m_tokens[0];

		return ec ? -1 : 0;
	}
Esempio n. 12
0
	std::string print_entry(bdecode_node const& e
		, bool single_line, int indent)
	{
		char indent_str[200];
		using std::memset;
		memset(indent_str, ' ', 200);
		indent_str[0] = ',';
		indent_str[1] = '\n';
		indent_str[199] = 0;
		if (indent < 197 && indent >= 0) indent_str[indent+2] = 0;
		std::string ret;
		switch (e.type())
		{
			case bdecode_node::none_t: return "none";
			case bdecode_node::int_t:
			{
				char str[100];
				snprintf(str, sizeof(str), "%" PRId64, e.int_value());
				return str;
			}
			case bdecode_node::string_t:
			{
				print_string(ret, e.string_ptr(), e.string_length(), single_line);
				return ret;
			}
			case bdecode_node::list_t:
			{
				ret += '[';
				bool one_liner = line_longer_than(e, 200) != -1 || single_line;

				if (!one_liner) ret += indent_str + 1;
				for (int i = 0; i < e.list_size(); ++i)
				{
					if (i == 0 && one_liner) ret += " ";
					ret += print_entry(e.list_at(i), single_line, indent + 2);
					if (i < e.list_size() - 1) ret += (one_liner?", ":indent_str);
					else ret += (one_liner?" ":indent_str+1);
				}
				ret += "]";
				return ret;
			}
			case bdecode_node::dict_t:
			{
				ret += "{";
				bool one_liner = line_longer_than(e, 200) != -1 || single_line;

				if (!one_liner) ret += indent_str+1;
				for (int i = 0; i < e.dict_size(); ++i)
				{
					if (i == 0 && one_liner) ret += " ";
					std::pair<std::string, bdecode_node> ent = e.dict_at(i);
					print_string(ret, ent.first.c_str(), ent.first.size(), true);
					ret += ": ";
					ret += print_entry(ent.second, single_line, indent + 2);
					if (i < e.dict_size() - 1) ret += (one_liner?", ":indent_str);
					else ret += (one_liner?" ":indent_str+1);
				}
				ret += "}";
				return ret;
			}
		}
		return ret;
	}
	// 'top_level' is extracting the file for a single-file torrent. The
	// distinction is that the filename is found in "name" rather than
	// "path"
	// root_dir is the name of the torrent, unless this is a single file
	// torrent, in which case it's empty.
	bool extract_single_file(bdecode_node const& dict, file_storage& files
		, std::string const& root_dir, ptrdiff_t info_ptr_diff, bool top_level
		, int& pad_file_cnt, error_code& ec)
	{
		if (dict.type() != bdecode_node::dict_t) return false;

		boost::uint32_t file_flags = get_file_attributes(dict);

		// symlinks have an implied "size" of zero. i.e. they use up 0 bytes of
		// the torrent payload space
		boost::int64_t const file_size = (file_flags & file_storage::flag_symlink)
			? 0
			: dict.dict_find_int_value("length", -1);
		if (file_size < 0 )
		{
			ec = errors::torrent_invalid_length;
			return false;
		}

		boost::int64_t const mtime = dict.dict_find_int_value("mtime", 0);

		std::string path = root_dir;
		std::string path_element;
		char const* filename = NULL;
		int filename_len = 0;

		if (top_level)
		{
			// prefer the name.utf-8 because if it exists, it is more likely to be
			// correctly encoded
			bdecode_node p = dict.dict_find_string("name.utf-8");
			if (!p) p = dict.dict_find_string("name");
			if (!p || p.string_length() == 0)
			{
				ec = errors::torrent_missing_name;
				return false;
			}

			filename = p.string_ptr() + info_ptr_diff;
			filename_len = p.string_length();
			while (filename_len > 0 && filename[0] == TORRENT_SEPARATOR)
			{
				filename += 1;
				filename_len -= 1;
			}
			sanitize_append_path_element(path, p.string_ptr(), p.string_length());
		}
		else
		{
			bdecode_node p = dict.dict_find_list("path.utf-8");
			if (!p) p = dict.dict_find_list("path");

			if (p && p.list_size() > 0)
			{
				std::size_t const orig_path_len = path.size();
				int const preallocate = path.size() + path_length(p, ec);
				if (ec) return false;
				path.reserve(preallocate);

				for (int i = 0, end(p.list_size()); i < end; ++i)
				{
					bdecode_node e = p.list_at(i);
					if (i == end - 1)
					{
						filename = e.string_ptr() + info_ptr_diff;
						filename_len = e.string_length();
					}
					while (filename_len > 0 && filename[0] == TORRENT_SEPARATOR)
					{
						filename += 1;
						filename_len -= 1;
					}
					sanitize_append_path_element(path, e.string_ptr(), e.string_length());
				}

				// if all path elements were sanitized away, we need to use another
				// name instead
				if (path.size() == orig_path_len)
				{
					path += TORRENT_SEPARATOR;
					path += "_";
				}
			}
			else if (file_flags & file_storage::flag_pad_file)
			{
				// pad files don't need a path element, we'll just store them
				// under the .pad directory
				char cnt[10];
				snprintf(cnt, sizeof(cnt), "%d", pad_file_cnt);
				path = combine_path(".pad", cnt);
				++pad_file_cnt;
			}
			else
			{
				ec = errors::torrent_missing_name;
				return false;
			}
		}

		// bitcomet pad file
		if (path.find("_____padding_file_") != std::string::npos)
			file_flags = file_storage::flag_pad_file;

		bdecode_node fh = dict.dict_find_string("sha1");
		char const* filehash = NULL;
		if (fh && fh.string_length() == 20)
			filehash = fh.string_ptr() + info_ptr_diff;

		std::string symlink_path;
		if (file_flags & file_storage::flag_symlink)
		{
			if (bdecode_node s_p = dict.dict_find_list("symlink path"))
			{
				int const preallocate = path_length(s_p, ec);
				if (ec) return false;
				symlink_path.reserve(preallocate);
				for (int i = 0, end(s_p.list_size()); i < end; ++i)
				{
					bdecode_node const& n = s_p.list_at(i);
					sanitize_append_path_element(symlink_path, n.string_ptr()
						, n.string_length());
				}
			}
		}
		else
		{
			file_flags &= ~file_storage::flag_symlink;
		}

		if (filename_len > path.length()
			|| path.compare(path.size() - filename_len, filename_len, filename
				, filename_len) != 0)
		{
			// if the filename was sanitized and differ, clear it to just use path
			filename = NULL;
			filename_len = 0;
		}

		files.add_file_borrow(filename, filename_len, path, file_size, file_flags, filehash
			, mtime, symlink_path);
		return true;
	}
Esempio n. 14
0
void get_item_observer::reply(msg const& m)
{
	public_key pk;
	signature sig;
	sequence_number seq{0};

	bdecode_node const r = m.message.dict_find_dict("r");
	if (!r)
	{
#ifndef TORRENT_DISABLE_LOGGING
		get_observer()->log(dht_logger::traversal, "[%p] missing response dict"
			, static_cast<void*>(algorithm()));
#endif
		timeout();
		return;
	}

	bdecode_node const k = r.dict_find_string("k");
	if (k && k.string_length() == public_key::len)
		std::memcpy(pk.bytes.data(), k.string_ptr(), public_key::len);

	bdecode_node const s = r.dict_find_string("sig");
	if (s && s.string_length() == signature::len)
		std::memcpy(sig.bytes.data(), s.string_ptr(), signature::len);

	bdecode_node const q = r.dict_find_int("seq");
	if (q)
	{
		seq = sequence_number(q.int_value());
	}
	else if (k && s)
	{
		timeout();
		return;
	}

	bdecode_node v = r.dict_find("v");
	if (v)
	{
		static_cast<get_item*>(algorithm())->got_data(v, pk, seq, sig);
	}

	find_data_observer::reply(m);
}