예제 #1
0
/*
 * Construct and return the list of xattr name:value pairs for the passed xattr
 * id
 *
 * There are two users for get_xattr(), Mksquashfs uses it to read the
 * xattrs from the filesystem on appending, and Unsquashfs uses it
 * to retrieve the xattrs for writing to disk.
 *
 * Unfortunately, the two users disagree on what to do with unknown
 * xattr prefixes, Mksquashfs wants to treat this as fatal otherwise
 * this will cause xattrs to be be lost on appending.  Unsquashfs
 * on the otherhand wants to retrieve the xattrs which are known and
 * to ignore the rest, this allows Unsquashfs to cope more gracefully
 * with future versions which may have unknown xattrs, as long as the
 * general xattr structure is adhered to, Unsquashfs should be able
 * to safely ignore unknown xattrs, and to write the ones it knows about,
 * this is better than completely refusing to retrieve all the xattrs.
 *
 * If ignore is TRUE then don't treat unknown xattr prefixes as
 * a failure to read the xattr.  
 */
struct xattr_list *get_xattr(int i, unsigned int *count, int ignore) {
	long long start;
	struct xattr_list *xattr_list = NULL;
	unsigned int offset;
	void *xptr;
	int j = 0, res = 1;

	TRACE("get_xattr\n");

	*count = xattr_ids[i].count;
	start = SQUASHFS_XATTR_BLK(xattr_ids[i].xattr) + xattr_table_start;
	offset = SQUASHFS_XATTR_OFFSET(xattr_ids[i].xattr);
	xptr = xattrs + get_xattr_block(start) + offset;

	TRACE("get_xattr: xattr_id %d, count %d, start %lld, offset %d\n", i, *count, start, offset);

	while (j < *count) {
		struct squashfs_xattr_entry entry;
		struct squashfs_xattr_val val;

		if (res != 0) {
			xattr_list = realloc(xattr_list, (j + 1) * sizeof(struct xattr_list));
			if (xattr_list == NULL)
				MEM_ERROR();
		}

		SQUASHFS_SWAP_XATTR_ENTRY(xptr, &entry);
		xptr += sizeof(entry);

		res = read_xattr_entry(&xattr_list[j], &entry, xptr);
		if (ignore && res == 0) {
			/* unknown prefix, but ignore flag is set */
			(*count)--;
			continue;
		}

		if (res != 1)
			goto failed;

		xptr += entry.size;

		TRACE("get_xattr: xattr %d, type %d, size %d, name %s\n", j, entry.type, entry.size, xattr_list[j].full_name);

		if (entry.type & SQUASHFS_XATTR_VALUE_OOL) {
			long long xattr;
			void *ool_xptr;

			xptr += sizeof(val);
			SQUASHFS_SWAP_LONG_LONGS(xptr, &xattr, 1);
			xptr += sizeof(xattr);
			start = SQUASHFS_XATTR_BLK(xattr) + xattr_table_start;
			offset = SQUASHFS_XATTR_OFFSET(xattr);
			ool_xptr = xattrs + get_xattr_block(start) + offset;
			SQUASHFS_SWAP_XATTR_VAL(ool_xptr, &val);
			xattr_list[j].value = ool_xptr + sizeof(val);
		} else {
			SQUASHFS_SWAP_XATTR_VAL(xptr, &val);
			xattr_list[j].value = xptr + sizeof(val);
			xptr += sizeof(val) + val.vsize;
		}

		TRACE("get_xattr: xattr %d, vsize %d\n", j, val.vsize);

		xattr_list[j++].vsize = val.vsize;
	}

	if (*count == 0)
		goto failed;

	return xattr_list;

 failed:
	free_xattr(xattr_list, j);

	return NULL;
}
예제 #2
0
파일: xattr.c 프로젝트: crossbuild/squashfs
int generate_xattrs(int xattrs, struct xattr_list *xattr_list)
{
	int total_size, i;
	int xattr_value_max;
	void *xp;
	long long xattr_disk;
	struct dupl_id *xattr_dupl;

	/*
	 * check if the file xattrs are a complete duplicate of a pre-existing
	 * id
	 */
	xattr_dupl = check_id_dupl(xattr_list, xattrs);
	if (xattr_dupl == NULL)
		return SQUASHFS_INVALID_XATTR;
	if(xattr_dupl->xattr_id != SQUASHFS_INVALID_XATTR)
		return xattr_dupl->xattr_id;
	 
	/*
	 * Scan the xattr_list deciding which type to assign to each
	 * xattr.  The choice is fairly straightforward, and depends on the
	 * size of each xattr name/value and the overall size of the
	 * resultant xattr list stored in the xattr metadata table.
	 *
	 * Choices are whether to store data inline or out of line.
	 *
	 * The overall goal is to optimise xattr scanning and lookup, and
	 * to enable the file system layout to scale from a couple of
	 * small xattr name/values to a large number of large xattr
	 * names/values without affecting performance.  While hopefully
	 * enabling the common case of a couple of small xattr name/values
	 * to be stored efficiently
	 *
	 * Code repeatedly scans, doing the following
	 *		move xattr data out of line if it exceeds
	 *		xattr_value_max.  Where xattr_value_max is
	 *		initially XATTR_INLINE_MAX.  If the final uncompressed
	 *		xattr list is larger than XATTR_TARGET_MAX then more
	 *		aggressively move xattr data out of line by repeatedly
	 *	 	setting inline threshold to 1/2, then 1/4, 1/8 of
	 *		XATTR_INLINE_MAX until target achieved or there's
	 *		nothing left to move out of line
	 */
	xattr_value_max = XATTR_INLINE_MAX;
	while(1) {
		for(total_size = 0, i = 0; i < xattrs; i++) {
			struct xattr_list *xattr = &xattr_list[i];
			xattr->type &= XATTR_PREFIX_MASK; /* all inline */
			if (xattr->vsize > xattr_value_max)
				xattr->type |= XATTR_VALUE_OOL;

			total_size += get_xattr_size(xattr);
		}

		/*
		 * If the total size of the uncompressed xattr list is <=
		 * XATTR_TARGET_MAX we're done
		 */
		if(total_size <= XATTR_TARGET_MAX)
			break;

		if(xattr_value_max == XATTR_VALUE_OOL_SIZE)
			break;

		/*
		 * Inline target not yet at minimum and so reduce it, and
		 * try again
		 */
		xattr_value_max /= 2;
		if(xattr_value_max < XATTR_VALUE_OOL_SIZE)
			xattr_value_max = XATTR_VALUE_OOL_SIZE;
	}

	/*
	 * Check xattr values for duplicates
	 */
	for(i = 0; i < xattrs; i++) {
		check_value_dupl(&xattr_list[i]);
	}

	/*
	 * Add each out of line value to the file system xattr table
	 * if it doesn't already exist as a duplicate
	 */
	for(i = 0; i < xattrs; i++) {
		struct xattr_list *xattr = &xattr_list[i];

		if((xattr->type & XATTR_VALUE_OOL) &&
				(xattr->ool_value == SQUASHFS_INVALID_BLK)) {
			struct squashfs_xattr_val val;
			int size = sizeof(val) + xattr->vsize;
			xp = get_xattr_space(size, &xattr->ool_value);
			val.vsize = xattr->vsize;
			SQUASHFS_SWAP_XATTR_VAL(&val, xp);
			memcpy(xp + sizeof(val), xattr->value, xattr->vsize);
		}
	}

	/*
	 * Create xattr list and add to file system xattr table
	 */
	get_xattr_space(0, &xattr_disk);
	for(i = 0; i < xattrs; i++) {
		struct xattr_list *xattr = &xattr_list[i];
		struct squashfs_xattr_entry entry;
		struct squashfs_xattr_val val;

		xp = get_xattr_space(sizeof(entry) + xattr->size, NULL);
		entry.type = xattr->type;
		entry.size = xattr->size;
		SQUASHFS_SWAP_XATTR_ENTRY(&entry, xp);
		memcpy(xp + sizeof(entry), xattr->name, xattr->size);

		if(xattr->type & XATTR_VALUE_OOL) {
			int size = sizeof(val) + XATTR_VALUE_OOL_SIZE;
			xp = get_xattr_space(size, NULL);
			val.vsize = XATTR_VALUE_OOL_SIZE;
			SQUASHFS_SWAP_XATTR_VAL(&val, xp);
			SQUASHFS_SWAP_LONG_LONGS(&xattr->ool_value, xp +
				sizeof(val), 1);
		} else {
			int size = sizeof(val) + xattr->vsize;
			xp = get_xattr_space(size, &xattr->ool_value);
			val.vsize = xattr->vsize;
			SQUASHFS_SWAP_XATTR_VAL(&val, xp);
			memcpy(xp + sizeof(val), xattr->value, xattr->vsize);
		}
	}

	/*
	 * Add to xattr id lookup table
	 */
	return get_xattr_id(xattrs, xattr_list, xattr_disk, xattr_dupl);
}
예제 #3
0
/*
 * Construct and return the list of xattr name:value pairs for the passed xattr
 * id
 */
struct xattr_list *get_xattr(int i, unsigned int *count)
{
	long long start;
	struct xattr_list *xattr_list = NULL;
	unsigned int offset;
	void *xptr;
	int j;

	TRACE("get_xattr\n");

	*count = xattr_ids[i].count;
	start = SQUASHFS_XATTR_BLK(xattr_ids[i].xattr) + xattr_table_start;
	offset = SQUASHFS_XATTR_OFFSET(xattr_ids[i].xattr);
	xptr = xattrs + get_xattr_block(start) + offset;

	TRACE("get_xattr: xattr_id %d, count %d, start %lld, offset %d\n", i,
			*count, start, offset);

	for(j = 0; j < *count; j++) {
		struct squashfs_xattr_entry entry;
		struct squashfs_xattr_val val;
		int res;

		xattr_list = realloc(xattr_list, (j + 1) *
						sizeof(struct xattr_list));
		if(xattr_list == NULL) {
			ERROR("Out of memory in get_xattrs\n");
			goto failed;
		}
			
		SQUASHFS_SWAP_XATTR_ENTRY(&entry, xptr);
		xptr += sizeof(entry);
		res = read_xattr_entry(&xattr_list[j], &entry, xptr);
		if(res != 1)
			goto failed;
		xptr += entry.size;
			
		TRACE("get_xattr: xattr %d, type %d, size %d, name %s\n", j,
			entry.type, entry.size, xattr_list[j].full_name); 

		if(entry.type & SQUASHFS_XATTR_VALUE_OOL) {
			long long xattr;
			void *ool_xptr;

			xptr += sizeof(val);
			SQUASHFS_SWAP_LONG_LONGS(&xattr, xptr, 1);
			xptr += sizeof(xattr);	
			start = SQUASHFS_XATTR_BLK(xattr) + xattr_table_start;
			offset = SQUASHFS_XATTR_OFFSET(xattr);
			ool_xptr = xattrs + get_xattr_block(start) + offset;
			SQUASHFS_SWAP_XATTR_VAL(&val, ool_xptr);
			xattr_list[j].value = ool_xptr + sizeof(val);
		} else {
			SQUASHFS_SWAP_XATTR_VAL(&val, xptr);
			xattr_list[j].value = xptr + sizeof(val);
			xptr += sizeof(val) + val.vsize;
		}

		TRACE("get_xattr: xattr %d, vsize %d\n", j, val.vsize);

		xattr_list[j].vsize = val.vsize;
	}

	return xattr_list;

failed:
	free(xattr_list);

	return NULL;
}