示例#1
0
/**
 * Get information about the filesystem mounted under the given directory
 * by filling the fs_info structure.
 */
static void
get_fs_info(const char *path, struct fs_info *fsi)
{
	filesize_t free_space = MAX_INT_VAL(filesize_t);
	filesize_t total_space = MAX_INT_VAL(filesize_t);

	g_assert(path);
	g_assert(fsi);

	(void) path;

#if defined(HAS_STATVFS)
	{
		/* statvfs() is a POSIX.1-2001 system call */
		struct statvfs buf;

		if (-1 == statvfs(path, &buf)) {
			g_warning("statvfs(\"%s\") failed: %s", path, g_strerror(errno));
		} else {
			free_space = ((filesize_t) 0 + buf.f_bavail) * buf.f_bsize;
			total_space = ((filesize_t) 0 + buf.f_blocks) * buf.f_frsize;
		}
	}
#elif defined(HAS_STATFS)
	{
		/* statfs() is deprecated but older systems may not have statvfs() */
		struct statfs buf;

		if (-1 == statfs(path, &buf)) {
			g_warning("statfs(\"%s\") failed: %s", path, g_strerror(errno));
		} else {
			free_space = ((filesize_t) 0 + buf.f_bavail) * buf.f_bsize;
			total_space = ((filesize_t) 0 + buf.f_blocks) * buf.f_bsize;
		}
	}
#elif defined(MINGW32)
	{
		struct mingw_statvfs buf;

		if (-1 == mingw_statvfs(path, &buf)) {
			g_warning("statvfs(\"%s\") failed: %s", path, g_strerror(errno));
		} else {
			free_space = ((filesize_t) 0 + buf.f_cavail) * buf.f_csize;
			total_space = ((filesize_t) 0 + buf.f_clusters) * buf.f_csize;
		}
	}
#endif	/* HAS_STATVFS || HAS_STATFS || MINGW32 */

	fsi->free_space = free_space;
	fsi->total_space = total_space;
}
示例#2
0
/**
 * Initialize security token caching.
 */
G_GNUC_COLD void
tcache_init(void)
{
	dbstore_kv_t kv = { KUID_RAW_SIZE, NULL, sizeof(struct tokdata),
		sizeof(struct tokdata) + MAX_INT_VAL(uint8) };
	dbstore_packing_t packing =
		{ serialize_tokdata, deserialize_tokdata, free_tokdata };

	g_assert(NULL == db_tokdata);
	g_assert(NULL == tcache_prune_ev);

	/* Legacy: remove after 0.97 -- RAM, 2011-05-03 */
	dbstore_move(settings_config_dir(), settings_dht_db_dir(), db_tcache_base);

	db_tokdata = dbstore_create(db_tcache_what, settings_dht_db_dir(),
		db_tcache_base, kv, packing, TOK_DB_CACHE_SIZE, kuid_hash, kuid_eq,
		GNET_PROPERTY(dht_storage_in_memory));

	dbmw_set_map_cache(db_tokdata, TOK_MAP_CACHE_SIZE);
	dbmw_set_debugging(db_tokdata, &tcache_dbmw_dbg);

	token_life = MIN(TOK_LIFE, token_lifetime());

	if (GNET_PROPERTY(dht_tcache_debug))
		g_debug("DHT cached token lifetime set to %u secs",
			(unsigned) token_life);

	tcache_prune_ev = cq_periodic_main_add(TCACHE_PRUNE_PERIOD,
		tcache_periodic_prune, NULL);
}
示例#3
0
/**
 * Write data to stream.
 *
 * @param os		the output stream
 * @param data		start of data to write
 * @param len		length of data to write
 *
 * @return size of data written, -1 on error.
 */
ssize_t
ostream_write(ostream_t *os, const void *data, size_t len)
{
	ssize_t w = (ssize_t) -1;

	ostream_check(os);
	len = MIN(len, MAX_INT_VAL(ssize_t));

	switch (os->type) {
	case OSTREAM_T_FILE:
		{
			size_t n = fwrite(data, len, 1, os->u.f);
			w = (0 == n) ? -1 : (ssize_t) len;
		}
		break;
	case OSTREAM_T_FD:
		w = write(os->u.fd, data, len);
		break;
	case OSTREAM_T_MEM:
		pmsg_slist_append(os->u.sl, data, len);
		w = len;
		break;
	case OSTREAM_T_PMSG:
		w = pmsg_write(os->u.mb, data, len);
		w = (len == UNSIGNED(w)) ? w : -1;
		break;
	case OSTREAM_T_MAX:
		g_assert_not_reached();
	}

	if (-1 == w)
		os->ioerr = TRUE;

	return w;
}
示例#4
0
/**
 * Add a port forwarding (*:ext_port -> addr:port) [IP or PPP connection].
 *
 * @param usd		the UPnP service to contact
 * @param proto		mapping protocol
 * @param ext_port	the mapped external port for which we want the mapping
 * @param int_addr	the internal client address
 * @param int_port	the internal port for which we want the mapping
 * @param desc		comment description
 * @param lease		lease duration (0 = permanent)
 * @param cb		callback to invoke when reply is available
 * @param arg		additional callback argument
 *
 * @return UPnP request handle if the SOAP RPC was initiated, NULL otherwise
 * (in which case callbacks will never be called).
 */
upnp_ctrl_t *
upnp_ctrl_AddPortMapping(const upnp_service_t *usd,
	enum upnp_map_proto proto, guint16 ext_port,
	host_addr_t int_addr, guint16 int_port,
	const char *desc, time_delta_t lease,
	upnp_ctrl_cb_t cb, void *arg)
{
	nv_pair_t *argv[8];
	char ext_port_buf[UINT16_DEC_BUFLEN];
	char int_port_buf[UINT16_DEC_BUFLEN];
	char int_addr_buf[HOST_ADDR_BUFLEN];
	char lease_buf[UINT32_DEC_BUFLEN];
	const char *protocol;
	const char *description;

	g_assert(lease >= 0);
	g_assert(lease <= MAX_INT_VAL(gint32));
	g_assert(ext_port != 0);
	g_assert(int_port != 0);

	int32_to_string_buf(ext_port, ext_port_buf, sizeof ext_port_buf);
	int32_to_string_buf(int_port, int_port_buf, sizeof int_port_buf);
	host_addr_to_string_buf(int_addr, int_addr_buf, sizeof int_addr_buf);
	protocol = upnp_map_proto_to_string(proto);
	int32_to_string_buf(lease, lease_buf, sizeof lease_buf);
	description = str_smsg("%s (%s)", desc, protocol);

	argv[0] = nv_pair_make_static_str(ARG_REMOTE_HOST, EMPTY);	/* Wildcard */
	argv[1] = nv_pair_make_static_str(ARG_EXTERNAL_PORT, ext_port_buf);
	argv[2] = nv_pair_make_static_str(ARG_PROTOCOL, protocol);
	argv[3] = nv_pair_make_static_str(ARG_INTERNAL_PORT, int_port_buf);
	argv[4] = nv_pair_make_static_str(ARG_INTERNAL_CLIENT, int_addr_buf);
	argv[5] = nv_pair_make_static_str(ARG_ENABLED, ONE);		/* Enable! */
	argv[6] = nv_pair_make_static_str(ARG_PORTMAP_DESC, description);
	argv[7] = nv_pair_make_static_str(ARG_LEASE_DURATION, lease_buf);

	/*
	 * TODO: when talking to a v2 WANIPConnection service, we can use
	 * the AddAnyPortMapping() call.  This will require that GTKG maintains
	 * knowledge about the remote port so that it can advertise that remote
	 * port instead of the local listening port.
	 *
	 * Attempts must be made to get the same external port for both TCP and UDP,
	 * or this will create problems to servents assuming that they will always
	 * be identical (like GTKG does when it uses the TCP listening port of
	 * a remote host to send a push-proxy request via UDP)..
	 *		--RAM, 2011-01-18
	 */

	return upnp_ctrl_launch(usd, "AddPortMapping",
		argv, G_N_ELEMENTS(argv), cb, arg,
		NULL);
}
示例#5
0
/**
 * Allocate a single block in the file, without extending it.
 *
 * @param db		the sdbm database
 * @param first		first block to consider
 *
 * @return the block number if found, 0 otherwise.
 */
static size_t
big_falloc(DBM *db, size_t first)
{
	DBMBIG *dbg = db->big;
	long max_bitmap = dbg->bitmaps;
	long i;
	long bmap;
	size_t first_bit;

	bmap = first / BIG_BITCOUNT;			/* Bitmap handling this block */
	first_bit = first & (BIG_BITCOUNT - 1);	/* Index within bitmap */

	g_assert(first_bit != 0);				/* Bit 0 is the bitmap itself */

	/*
	 * Loop through all the currently existing bitmaps.
	 */

	for (i = bmap; i < max_bitmap; i++) {
		size_t bno;

		if (!fetch_bitbuf(db, i))
			return 0;
		
		bno = bit_field_first_clear(dbg->bitbuf, first_bit, BIG_BITCOUNT - 1);
		if ((size_t) -1 == bno)
			continue;

		/*
		 * Found a free block.
		 */

		bit_field_set(dbg->bitbuf, bno);
		dbg->bitbuf_dirty = TRUE;

		/*
		 * Correct the block number corresponding to "bno", if we did
		 * not find it in bitmap #0.
		 */

		bno = size_saturate_add(bno, size_saturate_mult(BIG_BITCOUNT, i));

		/* Make sure we can represent the block number in 32 bits */
		g_assert(bno <= MAX_INT_VAL(guint32));

		return bno;		/* Allocated block number */
	}

	return 0;		/* No free block found */
}
示例#6
0
/**
 * Replace value data in-place.
 *
 * @param db		the sdbm database
 * @param bval		start of big value in the page
 * @param data		the new value
 * @param len		length of data
 *
 * @return 0 if OK, -1 on error with errno set.
 */
int
big_replace(DBM *db, char *bval, const char *data, size_t len)
{
	size_t old_len = big_length(bval);

	g_assert(size_is_non_negative(len));
	g_assert(bigblocks(old_len) == bigblocks(len));
	g_assert(len <= MAX_INT_VAL(guint32));

	/*
	 * Write data on the same blocks as before, since we know it will fit.
	 */

	poke_be32(bval, (guint32) len);		/* First 4 bytes: real data length */

	return big_store(db, bigval_blocks(bval), data, len);
}
示例#7
0
文件: spam.c 项目: Haxe/gtk-gnutella
/**
 * Load spam database from the supplied FILE.
 *
 * The current file format is as follows:
 *
 * # Comment
 * SHA1 <SHA-1>
 * ADDED <date>
 * END
 *
 * @returns the amount of entries loaded or -1 on failure.
 */
static G_GNUC_COLD gulong
spam_load(FILE *f)
{
	static const struct spam_item zero_item;
	struct spam_item item;
	char line[1024];
	guint line_no = 0;
	bit_array_t tag_used[BIT_ARRAY_SIZE(NUM_SPAM_TAGS)];
	gulong item_count = 0;

	g_assert(f);

	/* Reset state */
	item = zero_item;
	bit_array_init(tag_used, NUM_SPAM_TAGS);

	while (fgets(line, sizeof line, f)) {
		const char *tag_name, *value;
		char *sp, *nl;
		spam_tag_t tag;

		line_no++;

		nl = strchr(line, '\n');
		if (!nl) {
			/*
			 * If the line is too long or unterminated the file is either
			 * corrupt or was manually edited without respecting the
			 * exact format. If we continued, we would read from the
			 * middle of a line which could be the filename or ID.
			 */
			g_warning("spam_load(): "
				"line too long or missing newline in line %u",
				line_no);
			break;
		}
		*nl = '\0';

		/* Skip comments and empty lines */
		if (*line == '#' || *line == '\0')
			continue;

		sp = strchr(line, ' ');
		if (sp) {
			*sp = '\0';
			value = &sp[1];
		} else {
			value = strchr(line, '\0');
		}
		tag_name = line;

		tag = spam_string_to_tag(tag_name);
		g_assert(UNSIGNED(tag) < UNSIGNED(NUM_SPAM_TAGS));

		if (SPAM_TAG_UNKNOWN != tag && !bit_array_flip(tag_used, tag)) {
			g_warning("spam_load(): duplicate tag \"%s\" in entry in line %u",
				tag_name, line_no);
			continue;
		}
		
		switch (tag) {
		case SPAM_TAG_ADDED:
			{
				time_t t;
				
				t = date2time(value, tm_time());
				if ((time_t) -1 == t) {
					item.damaged = TRUE;
				}
			}
			break;
			
		case SPAM_TAG_SHA1:
			{
				if (strlen(value) != SHA1_BASE32_SIZE) {
					item.damaged = TRUE;
					g_warning("spam_load(): SHA-1 has wrong length.");
				} else {
					const struct sha1 *raw;

					raw = base32_sha1(value);
					if (raw)
						item.sha1 = *raw;
					else
						item.damaged = TRUE;
				}
			}
			break;

		case SPAM_TAG_NAME:
			{
				if ('\0' == value[0]) {
					item.damaged = TRUE;
					g_warning("spam_load(): Missing filename pattern.");
				} else if (!utf8_is_valid_string(value)) {
					item.damaged = TRUE;
					g_warning("spam_load(): Filename pattern is not UTF-8.");
				} else {
					item.name = h_strdup(value);
				}
			}
			break;

		case SPAM_TAG_SIZE:
			{
				const char *endptr;
				guint64 u;
				int error;
					
				u = parse_uint64(value, &endptr, 10, &error);
				if (error) {
					item.damaged = TRUE;
					g_warning("spam_load(): Cannot parse SIZE: %s", value);
				} else {
					item.min_size = u;
					item.max_size = u;

					if ('-' == endptr[0]) {
						u = parse_uint64(&endptr[1], &endptr, 10, &error);
						if (error) {
							item.damaged = TRUE;
							g_warning("spam_load(): Cannot parse SIZE: %s",
								value);
						}
						if (u < item.min_size) {
							item.damaged = TRUE;
							g_warning("spam_load(): "
								"Maximum size below minimum size");
						} else {
							item.max_size = u;
						}
					}
				}
			}
			break;

		case SPAM_TAG_END:
			if (
				!bit_array_get(tag_used, SPAM_TAG_SHA1) &&
				!bit_array_get(tag_used, SPAM_TAG_NAME)
			) {
				g_warning("spam_load(): missing SHA1 or NAME tag");
				item.damaged = TRUE;
			}
			if (!bit_array_get(tag_used, SPAM_TAG_ADDED)) {
				g_warning("spam_load(): missing ADDED tag");
				item.damaged = TRUE;
			}
			item.done = TRUE;
			break;

		case SPAM_TAG_UNKNOWN:
			/* Ignore */
			break;
			
		case NUM_SPAM_TAGS:
			g_assert_not_reached();
			break;
		}

		if (item.done && !item.damaged) {
			if (bit_array_get(tag_used, SPAM_TAG_SHA1)) {
				spam_sha1_add(&item.sha1);
				item_count++;
			}
			if (bit_array_get(tag_used, SPAM_TAG_NAME)) {
				if (!bit_array_get(tag_used, SPAM_TAG_SIZE)) {
					item.min_size = 0;
					item.max_size = MAX_INT_VAL(filesize_t);
				}
				if (
					spam_add_name_and_size(item.name,
						item.min_size, item.max_size)
				) {
					item.damaged = TRUE;	
				} else {
					item_count++;
				}
			}
		}

		if (item.damaged) {
			g_warning("Damaged spam entry in line %u: "
				"tag_name=\"%s\", value=\"%s\"",
				line_no, tag_name, value);
		}

		if (item.done) {
			/* Reset state */
			HFREE_NULL(item.name);
			item = zero_item;
			bit_array_clear_range(tag_used, 0, NUM_SPAM_TAGS - 1U);
		}
	}

	spam_sha1_sync();

	return item_count;
}
示例#8
0
/**
 * Add file to the current query hit.
 *
 * @return TRUE if we kept the file, FALSE if we did not include it in the hit.
 */
static bool
g2_build_qh2_add(struct g2_qh2_builder *ctx, const shared_file_t *sf)
{
	const sha1_t *sha1;
	g2_tree_t *h, *c;

	shared_file_check(sf);

	/*
	 * Make sure the file is still in the library.
	 */

	if (0 == shared_file_index(sf))
		return FALSE;

	/*
	 * On G2, the H/URN child is required, meaning we need the SHA1 at least.
	 */

	if (!sha1_hash_available(sf))
		return FALSE;

	/*
	 * Do not send duplicates, as determined by the SHA1 of the resource.
	 *
	 * A user may share several files with different names but the same SHA1,
	 * and if all of them are hits, we only want to send one instance.
	 *
	 * When generating hits for host-browsing, we do not care about duplicates
	 * and ctx->hs is NULL then.
	 */

	sha1 = shared_file_sha1(sf);		/* This is an atom */

	if (ctx->hs != NULL) {
		if (hset_contains(ctx->hs, sha1))
			return FALSE;

		hset_insert(ctx->hs, sha1);
	}

	/*
	 * Create the "H" child and attach it to the current tree.
	 */

	if (NULL == ctx->t)
		g2_build_qh2_start(ctx);

	h = g2_tree_alloc_empty("H");
	g2_tree_add_child(ctx->t, h);

	/*
	 * URN -- Universal Resource Name
	 *
	 * If there is a known TTH, then we can generate a bitprint, otherwise
	 * we just convey the SHA1.
	 */

	{
		const tth_t * const tth = shared_file_tth(sf);
		char payload[SHA1_RAW_SIZE + TTH_RAW_SIZE + sizeof G2_URN_BITPRINT];
		char *p = payload;

		if (NULL == tth) {
			p = mempcpy(p, G2_URN_SHA1, sizeof G2_URN_SHA1);
			p += clamp_memcpy(p, sizeof payload - ptr_diff(p, payload),
				sha1, SHA1_RAW_SIZE);
		} else {
			p = mempcpy(p, G2_URN_BITPRINT, sizeof G2_URN_BITPRINT);
			p += clamp_memcpy(p, sizeof payload - ptr_diff(p, payload),
				sha1, SHA1_RAW_SIZE);
			p += clamp_memcpy(p, sizeof payload - ptr_diff(p, payload),
				tth, TTH_RAW_SIZE);
		}

		g_assert(ptr_diff(p, payload) <= sizeof payload);

		c = g2_tree_alloc_copy("URN", payload, ptr_diff(p, payload));
		g2_tree_add_child(h, c);
	}

	/*
	 * URL -- empty to indicate that we share the file via uri-res.
	 */

	if (ctx->flags & QHIT_F_G2_URL) {
		uint known;
		uint16 csc;

		c = g2_tree_alloc_empty("URL");
		g2_tree_add_child(h, c);

		/*
		 * CSC -- if we know alternate sources, indicate how many in "CSC".
		 *
		 * This child is only emitted when they requested "URL".
		 */

		known = dmesh_count(sha1);
		csc = MIN(known, MAX_INT_VAL(uint16));

		if (csc != 0) {
			char payload[2];

			poke_le16(payload, csc);
			c = g2_tree_alloc_copy("CSC", payload, sizeof payload);
			g2_tree_add_child(h, c);
		}

		/*
		 * PART -- if we only have a partial file, indicate how much we have.
		 *
		 * This child is only emitted when they requested "URL".
		 */

		if (shared_file_is_partial(sf) && !shared_file_is_finished(sf)) {
			filesize_t available = shared_file_available(sf);
			char payload[8];	/* If we have to encode file size as 64-bit */
			uint32 av32;
			time_t mtime = shared_file_modification_time(sf);

			c = g2_tree_alloc_empty("PART");
			g2_tree_add_child(h, c);

			av32 = available;
			if (av32 == available) {
				/* Fits within a 32-bit quantity */
				poke_le32(payload, av32);
				g2_tree_set_payload(c, payload, sizeof av32, TRUE);
			} else {
				/* Encode as a 64-bit quantity then */
				poke_le64(payload, available);
				g2_tree_set_payload(c, payload, sizeof payload, TRUE);
			}

			/*
			 * GTKG extension: encode the last modification time of the
			 * partial file in an "MT" child.  This lets the other party
			 * determine whether the host is still able to actively complete
			 * the file.
			 */

			poke_le32(payload, (uint32) mtime);
			g2_tree_add_child(c,
				g2_tree_alloc_copy("MT", payload, sizeof(uint32)));
		}

		/*
		 * CT -- creation time of the resource (GTKG extension).
		 */

		{
			time_t create_time = shared_file_creation_time(sf);

			if ((time_t) -1 != create_time) {
				char payload[8];
				int n;

				create_time = MAX(0, create_time);
				n = vlint_encode(create_time, payload);
				g2_tree_add_child(h,
					g2_tree_alloc_copy("CT", payload, n));	/* No trailing 0s */
			}
		}
	}

	/*
	 * DN -- distinguished name.
	 *
	 * Note that the presence of DN also governs the presence of SZ if the
	 * file length does not fit a 32-bit unsigned quantity.
	 */

	if (ctx->flags & QHIT_F_G2_DN) {
		char payload[8];		/* If we have to encode file size as 64-bit */
		uint32 fs32;
		filesize_t fs = shared_file_size(sf);
		const char *name;
		const char *rp;

		c = g2_tree_alloc_empty("DN");

		fs32 = fs;
		if (fs32 == fs) {
			/* Fits within a 32-bit quantity */
			poke_le32(payload, fs32);
			g2_tree_set_payload(c, payload, sizeof fs32, TRUE);
		} else {
			/* Does not fit a 32-bit quantity, emit a SZ child */
			poke_le64(payload, fs);
			g2_tree_add_child(h,
				g2_tree_alloc_copy("SZ", payload, sizeof payload));
		}

		name = shared_file_name_nfc(sf);
		g2_tree_append_payload(c, name, shared_file_name_nfc_len(sf));
		g2_tree_add_child(h, c);

		/*
		 * GTKG extension: if there is a file path, expose it as a "P" child
		 * under the DN node.
		 */

		rp = shared_file_relative_path(sf);
		if (rp != NULL) {
			g2_tree_add_child(c, g2_tree_alloc_copy("P", rp, strlen(rp)));
		}
	}

	/*
	 * GTKG extension: if they requested alt-locs in the /Q2/I with "A", then
	 * send them some known alt-locs in an "ALT" child.
	 *
	 * Note that these alt-locs can be for Gnutella hosts: since both Gnutella
	 * and G2 share a common HTTP-based file transfer mechanism with compatible
	 * extra headers, there is no need to handle them separately.
	 */

	if (ctx->flags & QHIT_F_G2_ALT) {
		gnet_host_t hvec[G2_BUILD_QH2_MAX_ALT];
		int hcnt = 0;

		hcnt = dmesh_fill_alternate(sha1, hvec, N_ITEMS(hvec));

		if (hcnt > 0) {
			int i;

			c = g2_tree_alloc_empty("ALT");

			for (i = 0; i < hcnt; i++) {
				host_addr_t addr;
				uint16 port;

				addr = gnet_host_get_addr(&hvec[i]);
				port = gnet_host_get_port(&hvec[i]);

				if (host_addr_is_ipv4(addr)) {
					char payload[6];

					host_ip_port_poke(payload, addr, port, NULL);
					g2_tree_append_payload(c, payload, sizeof payload);
				}
			}

			/*
			 * If the payload is still empty, then drop the "ALT" child.
			 * Otherwise, attach it to the "H" node.
			 */

			if (NULL == g2_tree_node_payload(c, NULL)) {
				g2_tree_free_null(&c);
			} else {
				g2_tree_add_child(h, c);
			}
		}
	}

	/*
	 * Update the size of the query hit we're generating.
	 */

	ctx->current_size += g2_frame_serialize(h, NULL, 0);

	return TRUE;
}
示例#9
0
/**
 * Allocate "n" consecutive (sequential) blocks in the file, without
 * attempting to extend it.
 *
 * @param db		the sdbm database
 * @param bmap		bitmap number from which we need to start looking
 * @param n			amount of consecutive blocks we want
 *
 * @return the block number of the first "n" blocks if found, 0 if nothing
 * was found.
 */
static size_t
big_falloc_seq(DBM *db, int bmap, int n)
{
	DBMBIG *dbg = db->big;
	long max_bitmap = dbg->bitmaps;
	long i;

	g_assert(bmap >= 0);
	g_assert(n > 0);

	/*
	 * Loop through all the currently existing bitmaps, starting at the
	 * specified bitmap number.
	 */

	for (i = bmap; i < max_bitmap; i++) {
		size_t first;
		size_t j;
		int r;			/* Remaining blocks to allocate consecutively */

		if (!fetch_bitbuf(db, i))
			return 0;

		/*
		 * We start at bit #1 since bit #0 is the bitmap itself.
		 *
		 * Bit #0 should always be set but in case the file is corrupted,
		 * we don't want to start allocating data in the bitmap itself!.
		 */
		
		first = bit_field_first_clear(dbg->bitbuf, 1, BIG_BITCOUNT - 1);
		if ((size_t) -1 == first)
			continue;

		for (j = first + 1, r = n - 1; r > 0 && j < BIG_BITCOUNT; r--, j++) {
			if (bit_field_get(dbg->bitbuf, j))
				break;
		}

		/*
		 * If "r" is 0, we have no remaining page to allocate: we found our
		 * "n" consecutive free blocks.
		 */

		if (0 == r) {
			/*
			 * Mark the "n" consecutive blocks as busy.
			 */

			for (j = first, r = n; r > 0; r--, j++) {
				bit_field_set(dbg->bitbuf, j);
			}
			dbg->bitbuf_dirty = TRUE;

			/*
			 * Correct the block number corresponding to "first", if we did
			 * not find it in bitmap #0.
			 */

			first = size_saturate_add(first,
				size_saturate_mult(BIG_BITCOUNT, i));

			/* Make sure we can represent all block numbers in 32 bits */
			g_assert(size_saturate_add(first, n - 1) <= MAX_INT_VAL(guint32));

			return first;	/* "n" consecutive free blocks found */
		}
	}

	return 0;		/* No free block found */
}
示例#10
0
/**
 * Prepare reception of THEX data by building an appropriate RX stack.
 *
 * @return TRUE if we may continue with the download.
 */
bool
thex_download_receive(struct thex_download *ctx,
	filesize_t content_length,
	gnet_host_t *host, struct wrap_io *wio, uint32 flags)
{
	g_assert(ctx != NULL);

	gnet_host_copy(&ctx->host, host);

	/*
	 * Freeing of the RX stack must be asynchronous: each time we establish
	 * a new connection, dismantle the previous stack.  Otherwise the RX
	 * stack will be freed when the corresponding download structure is
	 * reclaimed.
	 */

	if (ctx->rx != NULL) {
		rx_free(ctx->rx);
		ctx->rx = NULL;
	}

	/*
	 * If there is a Content-Length indication in the HTTP reply, it is
	 * supplied here and will be used as a limit of the data we'll read.
	 *
	 * If there was none (for instance if the output is chunked), then 0
	 * is given and we'll use a hardwired maximum.
	 */

	if (content_length > MAX_INT_VAL(size_t))
		return FALSE;

	ctx->max_size = content_length ?
		(size_t) content_length : THEX_DOWNLOAD_MAX_SIZE;

	{
		struct rx_link_args args;

		args.cb = &thex_rx_link_cb;
		args.bws = bsched_in_select_by_addr(gnet_host_get_addr(&ctx->host));
		args.wio = wio;

		ctx->rx = rx_make(ctx, &ctx->host, rx_link_get_ops(), &args);
	}

	if (flags & THEX_DOWNLOAD_F_CHUNKED) {
		struct rx_chunk_args args;

		args.cb = &thex_rx_chunk_cb;

		ctx->rx = rx_make_above(ctx->rx, rx_chunk_get_ops(), &args);
	}

	if (flags & THEX_DOWNLOAD_F_INFLATE) {
		struct rx_inflate_args args;

		args.cb = &thex_rx_inflate_cb;

		ctx->rx = rx_make_above(ctx->rx, rx_inflate_get_ops(), &args);
	}

	rx_set_data_ind(ctx->rx, thex_download_data_ind);
	rx_enable(ctx->rx);

	return TRUE;
}
示例#11
0
	bin->vals[bin->nvals++] = entry;
}

/**
 * Makes a bin take as little memory as needed.
 */
static void
bin_compact(struct st_bin *bin)
{
	g_assert(bin->vals != NULL);	/* Or it would not have been allocated */

	bin->vals = hrealloc(bin->vals, bin->nvals * sizeof bin->vals[0]);
	bin->nslots = bin->nvals;
}

static guchar map[MAX_INT_VAL(guchar)];

static void
setup_map(void)
{
	static gboolean done;
	guint i;

	if (done)
		return;

	for (i = 0; i < G_N_ELEMENTS(map); i++)	{
		guchar c;

		if (i > 0 && utf8_byte_is_allowed(i)) {
			if (is_ascii_upper(i)) {
示例#12
0
/**
 * Writes the THEX data of the context ``ctx'' to the buffer
 * ``dest''. This must be called multiple times to retrieve the complete
 * data until zero is returned i.e., the end of file is reached.
 *
 * This routine deals with query hit data generation.
 *
 * @param special_upload an initialized THEX upload context.
 * @param dest the destination buffer.
 * @param size the amount of bytes ``dest'' can hold.
 *
 * @return -1 on failure, zero at the end-of-file condition or if size
 *         was zero. On success, the amount of bytes copied to ``dest''
 *         is returned.
 */
static ssize_t
thex_upload_read(struct special_upload *special_upload,
	void * const dest, size_t size)
{
	struct thex_upload *ctx = cast_to_thex_upload(special_upload);
	char *p = dest;

	g_assert(ctx);
	g_assert(0 == size || NULL != dest);
	g_assert(0 == ctx->size || NULL != ctx->data);
	g_assert(ctx->offset <= ctx->size);
	g_assert(UNSIGNED(ctx->state) < NUM_THEX_STATES);

	size = MIN(size, MAX_INT_VAL(ssize_t));

	while (size > 0) {

		switch (ctx->state) {
		case THEX_STATE_INITIAL:
			g_assert(NULL == ctx->data);
			if (!thex_upload_get_xml(ctx))
				goto error;
			ctx->state++;
			break;

		case THEX_STATE_XML_SENT:
			g_assert(NULL == ctx->data);
			if (!thex_upload_get_tree(ctx))
				goto error;
			ctx->state++;
			break;

		case THEX_STATE_XML:
		case THEX_STATE_TREE:
			{
				size_t n;

				g_assert(ctx->data);
				g_assert(ctx->size > ctx->offset);
				n = ctx->size - ctx->offset;
				n = MIN(n, size);

				memcpy(p, &ctx->data[ctx->offset], n);
				ctx->offset += n;
				p += n;
				size -= n;

				if (ctx->offset == ctx->size) {
					thex_upload_free_data(ctx);
					ctx->state++;
				}
			}
			break;
			
		case THEX_STATE_TREE_SENT:
			size = 0;
			break;	
		case NUM_THEX_STATES:
			g_assert_not_reached();
		}
	}

	return p - cast_to_char_ptr(dest);

error:
	errno = EIO;
	return (ssize_t)-1;
}