示例#1
0
文件: check.c 项目: AIdrifter/samba
/* Check that an unused record is valid. */
static bool tdb_check_free_record(struct tdb_context *tdb,
				  tdb_off_t off,
				  const struct tdb_record *rec,
				  unsigned char **hashes)
{
	if (!tdb_check_record(tdb, off, rec))
		return false;

	/* Mark this offset as a known value for the free list. */
	record_offset(hashes[0], off);
	/* And similarly if the next pointer is valid. */
	if (rec->next)
		record_offset(hashes[0], rec->next);
	return true;
}
示例#2
0
文件: GP_ZIP.c 项目: gfxprim/gfxprim
static int zip_load_next(gp_container *self, gp_pixmap **img,
                         gp_storage *storage,
                         gp_progress_cb *callback)
{
	struct zip_priv *priv = GP_CONTAINER_PRIV(self);
	int err;

	GP_DEBUG(1, "Trying to load next image from ZIP container");

	*img = NULL;

	do {
		err = zip_next_file(priv, img, storage, callback);
	} while (!*img && errno == 0);

	if (err)
		return 1;

	record_offset(priv, gp_io_tell(priv->io));

	priv->cur_pos++;
	self->cur_img = priv->cur_pos;

	return 0;
}
示例#3
0
文件: GP_ZIP.c 项目: gfxprim/gfxprim
static int load_next_offset(struct zip_priv *priv)
{
	struct zip_local_header header = {.file_name = NULL};
	int ret;
	long offset = gp_io_tell(priv->io);

	if ((ret = zip_load_header(priv->io, &header)))
		return ret;

	//TODO: Match image extension and signature
	record_offset(priv, offset);

	/* Seek to the next local header */
	seek_bytes(priv->io, (uint32_t)header.fname_len +
	                    (uint32_t)header.extf_len);
	seek_bytes(priv->io, header.comp_size);

	return 0;
}
示例#4
0
_PUBLIC_ int tdb_check(struct tdb_context *tdb,
	      int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
	      void *private_data)
{
	unsigned int h;
	unsigned char **hashes;
	tdb_off_t off, recovery_start;
	struct tdb_record rec;
	bool found_recovery = false;
	tdb_len_t dead;
	bool locked;

	/* Read-only databases use no locking at all: it's best-effort.
	 * We may have a write lock already, so skip that case too. */
	if (tdb->read_only || tdb->allrecord_lock.count != 0) {
		locked = false;
	} else {
		if (tdb_lockall_read(tdb) == -1)
			return -1;
		locked = true;
	}

	/* Make sure we know true size of the underlying file. */
	tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1);

	/* Header must be OK: also gets us the recovery ptr, if any. */
	if (!tdb_check_header(tdb, &recovery_start))
		goto unlock;

	/* We should have the whole header, too. */
	if (tdb->map_size < TDB_DATA_START(tdb->hash_size)) {
		tdb->ecode = TDB_ERR_CORRUPT;
		TDB_LOG((tdb, TDB_DEBUG_ERROR, "File too short for hashes\n"));
		goto unlock;
	}

	/* One big malloc: pointers then bit arrays. */
	hashes = (unsigned char **)calloc(
			1, sizeof(hashes[0]) * (1+tdb->hash_size)
			+ BITMAP_BITS / CHAR_BIT * (1+tdb->hash_size));
	if (!hashes) {
		tdb->ecode = TDB_ERR_OOM;
		goto unlock;
	}

	/* Initialize pointers */
	hashes[0] = (unsigned char *)(&hashes[1+tdb->hash_size]);
	for (h = 1; h < 1+tdb->hash_size; h++)
		hashes[h] = hashes[h-1] + BITMAP_BITS / CHAR_BIT;

	/* Freelist and hash headers are all in a row: read them. */
	for (h = 0; h < 1+tdb->hash_size; h++) {
		if (tdb_ofs_read(tdb, FREELIST_TOP + h*sizeof(tdb_off_t),
				 &off) == -1)
			goto free;
		if (off)
			record_offset(hashes[h], off);
	}

	/* For each record, read it in and check it's ok. */
	for (off = TDB_DATA_START(tdb->hash_size);
	     off < tdb->map_size;
	     off += sizeof(rec) + rec.rec_len) {
		if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec),
					   DOCONV()) == -1)
			goto free;
		switch (rec.magic) {
		case TDB_MAGIC:
		case TDB_DEAD_MAGIC:
			if (!tdb_check_used_record(tdb, off, &rec, hashes,
						   check, private_data))
				goto free;
			break;
		case TDB_FREE_MAGIC:
			if (!tdb_check_free_record(tdb, off, &rec, hashes))
				goto free;
			break;
		/* If we crash after ftruncate, we can get zeroes or fill. */
		case TDB_RECOVERY_INVALID_MAGIC:
		case 0x42424242:
			if (recovery_start == off) {
				found_recovery = true;
				break;
			}
			dead = tdb_dead_space(tdb, off);
			if (dead < sizeof(rec))
				goto corrupt;

			TDB_LOG((tdb, TDB_DEBUG_ERROR,
				 "Dead space at %d-%d (of %u)\n",
				 off, off + dead, tdb->map_size));
			rec.rec_len = dead - sizeof(rec);
			break;
		case TDB_RECOVERY_MAGIC:
			if (recovery_start != off) {
				TDB_LOG((tdb, TDB_DEBUG_ERROR,
					 "Unexpected recovery record at offset %d\n",
					 off));
				goto free;
			}
			found_recovery = true;
			break;
		default: ;
		corrupt:
			tdb->ecode = TDB_ERR_CORRUPT;
			TDB_LOG((tdb, TDB_DEBUG_ERROR,
				 "Bad magic 0x%x at offset %d\n",
				 rec.magic, off));
			goto free;
		}
	}

	/* Now, hashes should all be empty: each record exists and is referred
	 * to by one other. */
	for (h = 0; h < 1+tdb->hash_size; h++) {
		unsigned int i;
		for (i = 0; i < BITMAP_BITS / CHAR_BIT; i++) {
			if (hashes[h][i] != 0) {
				tdb->ecode = TDB_ERR_CORRUPT;
				TDB_LOG((tdb, TDB_DEBUG_ERROR,
					 "Hashes do not match records\n"));
				goto free;
			}
		}
	}

	/* We must have found recovery area if there was one. */
	if (recovery_start != 0 && !found_recovery) {
		TDB_LOG((tdb, TDB_DEBUG_ERROR,
			 "Expected a recovery area at %u\n",
			 recovery_start));
		goto free;
	}

	free(hashes);
	if (locked) {
		tdb_unlockall_read(tdb);
	}
	return 0;

free:
	free(hashes);
unlock:
	if (locked) {
		tdb_unlockall_read(tdb);
	}
	return -1;
}
示例#5
0
文件: check.c 项目: 0x24bin/winexe-1
int tdb_check(struct tdb_context *tdb,
	      int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
	      void *private_data)
{
	unsigned int h;
	unsigned char **hashes;
	tdb_off_t off, recovery_start;
	struct tdb_record rec;
	bool found_recovery = false;

	if (tdb_lockall(tdb) == -1)
		return -1;

	/* Make sure we know true size of the underlying file. */
	tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);

	/* Header must be OK: also gets us the recovery ptr, if any. */
	if (!tdb_check_header(tdb, &recovery_start))
		goto unlock;

	/* We should have the whole header, too. */
	if (tdb->map_size < TDB_DATA_START(tdb->header.hash_size)) {
		tdb->ecode = TDB_ERR_CORRUPT;
		TDB_LOG((tdb, TDB_DEBUG_ERROR, "File too short for hashes\n"));
		goto unlock;
	}

	/* One big malloc: pointers then bit arrays. */
	hashes = (unsigned char **)calloc(
			1, sizeof(hashes[0]) * (1+tdb->header.hash_size)
			+ BITMAP_BITS / CHAR_BIT * (1+tdb->header.hash_size));
	if (!hashes) {
		tdb->ecode = TDB_ERR_OOM;
		goto unlock;
	}

	/* Initialize pointers */
	hashes[0] = (unsigned char *)(&hashes[1+tdb->header.hash_size]);
	for (h = 1; h < 1+tdb->header.hash_size; h++)
		hashes[h] = hashes[h-1] + BITMAP_BITS / CHAR_BIT;

	/* Freelist and hash headers are all in a row: read them. */
	for (h = 0; h < 1+tdb->header.hash_size; h++) {
		if (tdb_ofs_read(tdb, FREELIST_TOP + h*sizeof(tdb_off_t),
				 &off) == -1)
			goto free;
		if (off)
			record_offset(hashes[h], off);
	}

	/* For each record, read it in and check it's ok. */
	for (off = TDB_DATA_START(tdb->header.hash_size);
	     off < tdb->map_size;
	     off += sizeof(rec) + rec.rec_len) {
		if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec),
					   DOCONV()) == -1)
			goto free;
		switch (rec.magic) {
		case TDB_MAGIC:
		case TDB_DEAD_MAGIC:
			if (!tdb_check_used_record(tdb, off, &rec, hashes,
						   check, private_data))
				goto free;
			break;
		case TDB_FREE_MAGIC:
			if (!tdb_check_free_record(tdb, off, &rec, hashes))
				goto free;
			break;
		case TDB_RECOVERY_MAGIC:
		case 0: /* Used for invalid (or in-progress) recovery area. */
			if (recovery_start != off) {
				TDB_LOG((tdb, TDB_DEBUG_ERROR,
					 "Unexpected recovery record at offset %d\n",
					 off));
				goto free;
			}
			found_recovery = true;
			break;
		default:
			tdb->ecode = TDB_ERR_CORRUPT;
			TDB_LOG((tdb, TDB_DEBUG_ERROR,
				 "Bad magic 0x%x at offset %d\n",
				 rec.magic, off));
			goto free;
		}
	}

	/* Now, hashes should all be empty: each record exists and is referred
	 * to by one other. */
	for (h = 0; h < 1+tdb->header.hash_size; h++) {
		unsigned int i;
		for (i = 0; i < BITMAP_BITS / CHAR_BIT; i++) {
			if (hashes[h][i] != 0) {
				tdb->ecode = TDB_ERR_CORRUPT;
				TDB_LOG((tdb, TDB_DEBUG_ERROR,
					 "Hashes do not match records\n"));
				goto free;
			}
		}
	}

	/* We must have found recovery area if there was one. */
	if (recovery_start != 0 && !found_recovery) {
		TDB_LOG((tdb, TDB_DEBUG_ERROR,
			 "Expected %s recovery area, got %s\n",
			 recovery_start ? "a" : "no",
			 found_recovery ? "one" : "none"));
		goto free;
	}

	free(hashes);
	tdb_unlockall(tdb);
	return 0;

free:
	free(hashes);
unlock:
	tdb_unlockall(tdb);
	return -1;
}
示例#6
0
文件: check.c 项目: Alexander--/samba
/* Check that an in-use record is valid. */
static bool tdb_check_used_record(struct tdb_context *tdb,
				  tdb_off_t off,
				  const struct tdb_record *rec,
				  unsigned char **hashes,
				  int (*check)(TDB_DATA, TDB_DATA, void *),
				  void *private_data)
{
	TDB_DATA key, data;
	tdb_len_t len;

	if (!tdb_check_record(tdb, off, rec))
		return false;

	/* key + data + tailer must fit in record */
	len = rec->key_len;
	len += rec->data_len;
	if (len < rec->data_len) {
		/* overflow */
		TDB_LOG((tdb, TDB_DEBUG_ERROR, "Record lengths overflow\n"));
		return false;
	}
	len += sizeof(tdb_off_t);
	if (len < sizeof(tdb_off_t)) {
		/* overflow */
		TDB_LOG((tdb, TDB_DEBUG_ERROR, "Record lengths overflow\n"));
		return false;
	}

	if (len > rec->rec_len) {
		TDB_LOG((tdb, TDB_DEBUG_ERROR,
			 "Record offset %u too short for contents\n", off));
		return false;
	}

	key = get_bytes(tdb, off + sizeof(*rec), rec->key_len);
	if (!key.dptr)
		return false;

	if (tdb->hash_fn(&key) != rec->full_hash) {
		TDB_LOG((tdb, TDB_DEBUG_ERROR,
			 "Record offset %u has incorrect hash\n", off));
		goto fail_put_key;
	}

	/* Mark this offset as a known value for this hash bucket. */
	record_offset(hashes[BUCKET(rec->full_hash)+1], off);
	/* And similarly if the next pointer is valid. */
	if (rec->next)
		record_offset(hashes[BUCKET(rec->full_hash)+1], rec->next);

	/* If they supply a check function and this record isn't dead,
	   get data and feed it. */
	if (check && rec->magic != TDB_DEAD_MAGIC) {
		data = get_bytes(tdb, off + sizeof(*rec) + rec->key_len,
				 rec->data_len);
		if (!data.dptr)
			goto fail_put_key;

		if (check(key, data, private_data) == -1)
			goto fail_put_data;
		put_bytes(tdb, data);
	}

	put_bytes(tdb, key);
	return true;

fail_put_data:
	put_bytes(tdb, data);
fail_put_key:
	put_bytes(tdb, key);
	return false;
}