Esempio n. 1
0
/*
 * If the stack is NULL, create and initialise it.
 * If is is not NULL, check it still has space - if not, double its size.
 */
static int stack_check(ea_file_impl_t *f)
{
	if (f->ef_depth == NULL) {
		if ((f->ef_depth =
		    ea_alloc(DEFAULT_ENTRIES * sizeof (ea_file_depth_t)))
		    == NULL) {
			/* exacct_errno set above. */
			return (-1);
		}
		bzero(f->ef_depth, DEFAULT_ENTRIES * sizeof (ea_file_depth_t));
		f->ef_mxdeep = DEFAULT_ENTRIES;
		f->ef_ndeep = -1;
	} else if (f->ef_ndeep + 1 >= f->ef_mxdeep) {
		ea_file_depth_t *newstack;

		if ((newstack =
		    ea_alloc(f->ef_mxdeep * 2 * sizeof (ea_file_depth_t)))
		    == NULL) {
			/* exacct_errno set above. */
			return (-1);
		}
		bcopy(f->ef_depth, newstack,
		    f->ef_mxdeep * sizeof (ea_file_depth_t));
		bzero(newstack + f->ef_mxdeep,
		    f->ef_mxdeep * sizeof (ea_file_depth_t));
		ea_free(f->ef_depth, f->ef_mxdeep * sizeof (ea_file_depth_t));
		f->ef_mxdeep *= 2;
		f->ef_depth = newstack;
	}
	return (0);
}
Esempio n. 2
0
/*
 * Free a stack.
 */
static void stack_free(ea_file_impl_t *f)
{
	if (f->ef_depth != NULL) {
		ea_free(f->ef_depth, f->ef_mxdeep * sizeof (ea_file_depth_t));
		f->ef_depth = NULL;
	}
	f->ef_mxdeep = 0;
	f->ef_ndeep = -1;
}
Esempio n. 3
0
int
ea_write_object(ea_file_t *ef, ea_object_t *obj)
{
	ea_size_t sz;
	void *buf;
	ea_file_impl_t *f = (ea_file_impl_t *)ef;

	/*
	 * If we weren't opened for writing, this call fails.
	 */
	if ((f->ef_oflags & O_RDWR) == 0 &&
	    (f->ef_oflags & O_WRONLY) == 0) {
		EXACCT_SET_ERR(EXR_NOTSUPP);
		return (-1);
	}

	/* Pack with a null buffer to get the size. */
	sz = ea_pack_object(obj, NULL, 0);
	if (sz == -1 || (buf = ea_alloc(sz)) == NULL) {
		/* exacct_error set above. */
		return (-1);
	}
	if (ea_pack_object(obj, buf, sz) == (size_t)-1) {
		ea_free(buf, sz);
		/* exacct_error set above. */
		return (-1);
	}
	if (fwrite(buf, sizeof (char), sz, f->ef_fp) != sz) {
		ea_free(buf, sz);
		EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
		return (-1);
	}
	ea_free(buf, sz);
	EXACCT_SET_ERR(EXR_OK);
	return (0);
}
Esempio n. 4
0
/*
 * unpack_group() recursively unpacks record groups from the buffer tucked
 * within the passed ea_file, and attaches them to grp.
 */
static int
unpack_group(ea_file_impl_t *f, ea_object_t *grp, int flag)
{
	ea_object_t *obj;
	uint_t nobjs = grp->eo_group.eg_nobjs;
	int i;

	/*
	 * Set the group's object count to zero, as we will rebuild it via the
	 * individual object attachments.
	 */
	grp->eo_group.eg_nobjs = 0;
	grp->eo_group.eg_objs = NULL;

	for (i = 0; i < nobjs; i++) {
		if ((obj = ea_alloc(sizeof (ea_object_t))) == NULL) {
			/* exacct_errno set above. */
			return (-1);
		}
		obj->eo_next = NULL;
		if (xget_object(f, obj, bufread_wrapper, bufseek_wrapper,
			    bufpos_wrapper, flag) == -1) {
			ea_free(obj, sizeof (ea_object_t));
			/* exacct_errno set above. */
			return (-1);
		}

		(void) ea_attach_to_group(grp, obj);

		if (obj->eo_type == EO_GROUP &&
		    unpack_group(f, obj, flag) == -1) {
			/* exacct_errno set above. */
			return (-1);
		}
	}

	if (nobjs != grp->eo_group.eg_nobjs) {
		EXACCT_SET_ERR(EXR_CORRUPT_FILE);
		return (-1);
	}
	EXACCT_SET_ERR(EXR_OK);
	return (0);
}
Esempio n. 5
0
/*
 * Read in the specified number of objects, returning the same data
 * structure that would have originally been passed to ea_write().
 */
ea_object_t *
ea_get_object_tree(ea_file_t *ef, uint32_t nobj)
{
	ea_object_t *first_obj, *prev_obj, *obj;

	first_obj = prev_obj = NULL;
	while (nobj--) {
		/* Allocate space for the new object. */
		obj = ea_alloc(sizeof (ea_object_t));
		bzero(obj, sizeof (*obj));

		/* Read it in. */
		if (ea_get_object(ef, obj) == -1) {
			ea_free(obj, sizeof (ea_object_t));
			if (first_obj != NULL) {
				ea_free_object(first_obj, EUP_ALLOC);
			}
			return (NULL);
		}

		/* Link it into the list. */
		if (first_obj == NULL) {
			first_obj = obj;
		}
		if (prev_obj != NULL) {
			prev_obj->eo_next = obj;
		}
		prev_obj = obj;

		/* Recurse if the object is a group with contents. */
		if (obj->eo_type == EO_GROUP && obj->eo_group.eg_nobjs > 0) {
			if ((obj->eo_group.eg_objs = ea_get_object_tree(ef,
			    obj->eo_group.eg_nobjs)) == NULL) {
				/* exacct_error set above. */
				ea_free_object(first_obj, EUP_ALLOC);
				return (NULL);
			}
		}
	}
	EXACCT_SET_ERR(EXR_OK);
	return (first_obj);
}
Esempio n. 6
0
/*
 * ea_close() performs all appropriate close operations on the open exacct file,
 * including releasing any memory allocated while parsing the file.
 */
int
ea_close(ea_file_t *ef)
{
	ea_file_impl_t *f = (ea_file_impl_t *)ef;

	if (f->ef_creator != NULL)
		ea_strfree(f->ef_creator);
	if (f->ef_hostname != NULL)
		ea_strfree(f->ef_hostname);

	ea_free(f->ef_depth, f->ef_mxdeep * sizeof (ea_file_depth_t));

	if (fclose(f->ef_fp)) {
		EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
		return (-1);
	}

	EXACCT_SET_ERR(EXR_OK);
	return (0);
}
Esempio n. 7
0
static int
write_header(ea_file_t *ef)
{
	ea_object_t hdr_grp;
	ea_object_t vers_obj;
	ea_object_t creator_obj;
	ea_object_t filetype_obj;
	ea_object_t hostname_obj;
	uint32_t bskip;
	const uint32_t version = EXACCT_VERSION;
	ea_file_impl_t *f = (ea_file_impl_t *)ef;
	void *buf;
	size_t bufsize;
	char hostbuf[SYSINFO_BUFSIZE];
	int error = EXR_OK;

	bzero(&hdr_grp, sizeof (ea_object_t));
	bzero(&vers_obj, sizeof (ea_object_t));
	bzero(&creator_obj, sizeof (ea_object_t));
	bzero(&filetype_obj, sizeof (ea_object_t));
	bzero(&hostname_obj, sizeof (ea_object_t));
	bzero(hostbuf, SYSINFO_BUFSIZE);

	(void) sysinfo(SI_HOSTNAME, hostbuf, SYSINFO_BUFSIZE);

	if (ea_set_item(&vers_obj, EXT_UINT32 | EXC_DEFAULT | EXD_VERSION,
		    (void *)&version, 0) == -1 ||
	    ea_set_item(&creator_obj, EXT_STRING | EXC_DEFAULT | EXD_CREATOR,
		    f->ef_creator, strlen(f->ef_creator)) == -1 ||
	    ea_set_item(&filetype_obj, EXT_STRING | EXC_DEFAULT | EXD_FILETYPE,
		    EXACCT_HDR_STR, strlen(EXACCT_HDR_STR)) == -1 ||
	    ea_set_item(&hostname_obj, EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME,
		    hostbuf, strlen(hostbuf)) == -1) {
		error = ea_error();
		goto cleanup1;
	}

	(void) ea_set_group(&hdr_grp,
	    EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER);
	(void) ea_attach_to_group(&hdr_grp, &vers_obj);
	(void) ea_attach_to_group(&hdr_grp, &creator_obj);
	(void) ea_attach_to_group(&hdr_grp, &filetype_obj);
	(void) ea_attach_to_group(&hdr_grp, &hostname_obj);

	/* Get the required size by passing a null buffer. */
	bufsize = ea_pack_object(&hdr_grp, NULL, 0);
	if ((buf = ea_alloc(bufsize)) == NULL) {
		error = ea_error();
		goto cleanup1;
	}

	if (ea_pack_object(&hdr_grp, buf, bufsize) == (size_t)-1) {
		error = ea_error();
		goto cleanup2;
	}

	/*
	 * To prevent reading the header when reading the file backwards,
	 * set the large backskip of the header group to 0 (last 4 bytes).
	 */
	bskip = 0;
	exacct_order32(&bskip);
	bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip),
	    sizeof (bskip));

	if (fwrite(buf, sizeof (char), bufsize, f->ef_fp) != bufsize ||
	    fflush(f->ef_fp) == EOF) {
		error = EXR_SYSCALL_FAIL;
		goto cleanup2;
	}

cleanup2:
	ea_free(buf, bufsize);
cleanup1:
	(void) ea_free_item(&vers_obj, EUP_ALLOC);
	(void) ea_free_item(&creator_obj, EUP_ALLOC);
	(void) ea_free_item(&filetype_obj, EUP_ALLOC);
	(void) ea_free_item(&hostname_obj, EUP_ALLOC);
	EXACCT_SET_ERR(error);
	return (error == EXR_OK ? 0 : -1);
}
Esempio n. 8
0
/*
 * ea_unpack_object() can be considered as a finite series of get operations on
 * a given buffer, that rebuilds the hierarchy of objects compacted by a pack
 * operation.  Because there is complex state associated with the group depth,
 * ea_unpack_object() must complete as one operation on a given buffer.
 */
ea_object_type_t
ea_unpack_object(ea_object_t **objp, int flag, void *buf, size_t bufsize)
{
	ea_file_impl_t fake;
	ea_object_t *obj;
	ea_object_type_t first_obj_type;

	*objp = NULL;
	if (buf == NULL) {
		EXACCT_SET_ERR(EXR_INVALID_BUF);
		return (EO_ERROR);
	}

	/* Set up the structures needed for unpacking */
	bzero(&fake, sizeof (ea_file_impl_t));
	if (stack_check(&fake) == -1) {
		/* exacct_errno set above. */
		return (EO_ERROR);
	}
	fake.ef_buf = buf;
	fake.ef_bufsize = bufsize;

	/* Unpack the first object in the buffer - this should succeed. */
	if ((obj = ea_alloc(sizeof (ea_object_t))) == NULL) {
		stack_free(&fake);
		/* exacct_errno set above. */
		return (EO_ERROR);
	}
	obj->eo_next = NULL;
	if ((first_obj_type = xget_object(&fake, obj, bufread_wrapper,
	    bufseek_wrapper, bufpos_wrapper, flag)) == -1) {
		stack_free(&fake);
		ea_free(obj, sizeof (ea_object_t));
		/* exacct_errno set above. */
		return (EO_ERROR);
	}

	if (obj->eo_type == EO_GROUP && unpack_group(&fake, obj, flag) == -1) {
		stack_free(&fake);
		ea_free_object(obj, flag);
		/* exacct_errno set above. */
		return (EO_ERROR);
	}
	*objp = obj;

	/*
	 * There may be other objects in the buffer - if so, chain them onto
	 * the end of the list.  We have reached the end of the list when
	 * xget_object() returns -1 with exacct_error set to EXR_EOF.
	 */
	for (;;) {
		if ((obj = ea_alloc(sizeof (ea_object_t))) == NULL) {
			stack_free(&fake);
			ea_free_object(*objp, flag);
			*objp = NULL;
			/* exacct_errno set above. */
			return (EO_ERROR);
		}
		obj->eo_next = NULL;
		if (xget_object(&fake, obj, bufread_wrapper, bufseek_wrapper,
			    bufpos_wrapper, flag) == -1) {
			stack_free(&fake);
			ea_free(obj, sizeof (ea_object_t));
			if (ea_error() == EXR_EOF) {
				EXACCT_SET_ERR(EXR_OK);
				return (first_obj_type);
			} else {
				ea_free_object(*objp, flag);
				*objp = NULL;
				/* exacct_error set above. */
				return (EO_ERROR);
			}
		}

		(void) ea_attach_to_object(*objp, obj);

		if (obj->eo_type == EO_GROUP &&
		    unpack_group(&fake, obj, flag) == -1) {
			stack_free(&fake);
			ea_free(obj, sizeof (ea_object_t));
			ea_free_object(*objp, flag);
			*objp = NULL;
			/* exacct_errno set above. */
			return (EO_ERROR);
		}
	}
}
Esempio n. 9
0
/*
 * xget_object() contains the logic for extracting an individual object from a
 * packed buffer, which it consumes using xread() and xseek() operations
 * provided by the caller.  flags may be set to either EUP_ALLOC, in which case
 * new memory is allocated for the variable length items unpacked, or
 * EUP_NOALLOC, in which case item data pointer indicate locations within the
 * buffer, using the provided xpos() function.  EUP_NOALLOC is generally not
 * useful for callers representing interaction with actual file streams, and
 * should not be specified thereby.
 */
static ea_object_type_t
xget_object(
    ea_file_impl_t *f,
    ea_object_t *obj,
    size_t (*xread)(ea_file_impl_t *, void *, size_t),
    off_t (*xseek)(ea_file_impl_t *, off_t),
    void *(*xpos)(ea_file_impl_t *),
    int flags)
{
	ea_size_t sz;
	uint32_t gp_backskip, scratch32;
	void *buf;
	size_t r;

	/* Read the catalog tag. */
	if ((r = xread(f, &obj->eo_catalog, sizeof (ea_catalog_t))) == 0) {
		EXACCT_SET_ERR(EXR_EOF);
		return (EO_ERROR);
	} else if (r != sizeof (ea_catalog_t)) {
		EXACCT_SET_ERR(EXR_CORRUPT_FILE);
		return (EO_ERROR);
	}
	exacct_order32(&obj->eo_catalog);

	/*
	 * If this is a record group, we treat it separately:  only record
	 * groups cause us to allocate new depth frames.
	 */
	if ((obj->eo_catalog & EXT_TYPE_MASK) == EXT_GROUP) {
		obj->eo_type = EO_GROUP;

		/* Read size field, and number of objects. */
		if (xread(f, &sz, sizeof (ea_size_t)) != sizeof (ea_size_t)) {
			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
			return (EO_ERROR);
		}
		exacct_order64(&sz);
		if (xread(f, &obj->eo_group.eg_nobjs, sizeof (uint32_t)) !=
		    sizeof (uint32_t)) {
			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
			return (EO_ERROR);
		}
		exacct_order32(&obj->eo_group.eg_nobjs);

		/* Now read the group's small backskip. */
		if (xread(f, &gp_backskip, sizeof (uint32_t)) !=
		    sizeof (uint32_t)) {
			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
			return (EO_ERROR);
		}

		/* Push a new depth stack frame. */
		if (stack_new_group(f, obj->eo_group.eg_nobjs) != 0) {
			/* exacct_error set above */
			return (EO_ERROR);
		}

		/*
		 * If the group has no items, we now need to position to the
		 * end of the group, because there will be no subsequent calls
		 * to process the group, it being empty.
		 */
		if (obj->eo_group.eg_nobjs == 0) {
			if (stack_next_object(f, xread) == -1) {
				/* exacct_error set above. */
				return (EO_ERROR);
			}
		}

		f->ef_advance = 0;
		EXACCT_SET_ERR(EXR_OK);
		return (obj->eo_type);
	}

	/*
	 * Otherwise we are reading an item.
	 */
	obj->eo_type = EO_ITEM;
	switch (obj->eo_catalog & EXT_TYPE_MASK) {
	case EXT_STRING:
	case EXT_EXACCT_OBJECT:
	case EXT_RAW:
		if (xread(f, &sz, sizeof (ea_size_t)) != sizeof (ea_size_t)) {
			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
			return (EO_ERROR);
		}
		exacct_order64(&sz);
		/*
		 * Subtract backskip value from size.
		 */
		sz -= sizeof (uint32_t);
		if ((flags & EUP_ALLOC_MASK) == EUP_NOALLOC) {
			buf = xpos(f);
			if (xseek(f, sz) == -1) {
				EXACCT_SET_ERR(EXR_CORRUPT_FILE);
				return (EO_ERROR);
			}
		} else {
			if ((buf = ea_alloc(sz)) == NULL)
				/* exacct_error set above. */
				return (EO_ERROR);
			if (xread(f, buf, sz) != sz) {
				ea_free(buf, sz);
				EXACCT_SET_ERR(EXR_CORRUPT_FILE);
				return (EO_ERROR);
			}
		}
		obj->eo_item.ei_string = buf;
		/*
		 * Maintain our consistent convention that string lengths
		 * include the terminating NULL character.
		 */
		obj->eo_item.ei_size = sz;
		break;
	case EXT_UINT8:
		if (xread(f, &obj->eo_item.ei_uint8, sizeof (uint8_t)) !=
		    sizeof (uint8_t)) {
			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
			return (EO_ERROR);
		}
		obj->eo_item.ei_size = sizeof (uint8_t);
		break;
	case EXT_UINT16:
		if (xread(f, &obj->eo_item.ei_uint16, sizeof (uint16_t)) !=
		    sizeof (uint16_t)) {
			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
			return (EO_ERROR);
		}
		exacct_order16(&obj->eo_item.ei_uint16);
		obj->eo_item.ei_size = sizeof (uint16_t);
		break;
	case EXT_UINT32:
		if (xread(f, &obj->eo_item.ei_uint32, sizeof (uint32_t)) !=
		    sizeof (uint32_t)) {
			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
			return (EO_ERROR);
		}
		exacct_order32(&obj->eo_item.ei_uint32);
		obj->eo_item.ei_size = sizeof (uint32_t);
		break;
	case EXT_UINT64:
		if (xread(f, &obj->eo_item.ei_uint64, sizeof (uint64_t)) !=
		    sizeof (uint64_t)) {
			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
			return (EO_ERROR);
		}
		exacct_order64(&obj->eo_item.ei_uint64);
		obj->eo_item.ei_size = sizeof (uint64_t);
		break;
	case EXT_DOUBLE:
		if (xread(f, &obj->eo_item.ei_double, sizeof (double)) !=
		    sizeof (double)) {
			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
			return (EO_ERROR);
		}
		exacct_order64((uint64_t *)&obj->eo_item.ei_double);
		obj->eo_item.ei_size = sizeof (double);
		break;
	default:
		/*
		 * We've encountered an unknown type value.  Flag the error and
		 * exit.
		 */
		EXACCT_SET_ERR(EXR_CORRUPT_FILE);
		return (EO_ERROR);
	}

	/*
	 * Advance over current large backskip value,
	 * and position at the start of the next object.
	 */
	if (xread(f, &scratch32, sizeof (scratch32)) != sizeof (scratch32)) {
		EXACCT_SET_ERR(EXR_CORRUPT_FILE);
		return (EO_ERROR);
	}
	if (stack_next_object(f, xread) == -1) {
		/* exacct_error set above. */
		return (EO_ERROR);
	}

	f->ef_advance = 0;
	EXACCT_SET_ERR(EXR_OK);
	return (obj->eo_type);
}
Esempio n. 10
0
/*
 * Convert the perl form of an ::Object into the corresponding exacct form.
 * This is used prior to writing an ::Object to a file, or passing it to
 * putacct.  This is only required for embedded items and groups - for normal
 * items it is a no-op.
 */
ea_object_t *
deflate_xs_ea_object(SV *sv)
{
	xs_ea_object_t	*xs_obj;
	ea_object_t	*ea_obj;

	/* Get the source xs_ea_object_t. */
	PERL_ASSERT(sv != NULL);
	sv = SvRV(sv);
	PERL_ASSERT(sv != NULL);
	xs_obj = INT2PTR(xs_ea_object_t *, SvIV(sv));
	PERL_ASSERT(xs_obj != NULL);
	ea_obj = xs_obj->ea_obj;
	PERL_ASSERT(ea_obj != NULL);

	/* Break any list this object is a part of. */
	ea_obj->eo_next = NULL;

	/* Deal with Items containing embedded Objects. */
	if (IS_EMBED_ITEM(xs_obj)) {
		xs_ea_object_t	*child_xs_obj;
		SV		*perl_obj;
		size_t		bufsz;

		/* Get the underlying perl object an deflate that in turn. */
		perl_obj = xs_obj->perl_obj;
		PERL_ASSERT(perl_obj != NULL);
		deflate_xs_ea_object(perl_obj);
		perl_obj = SvRV(perl_obj);
		PERL_ASSERT(perl_obj != NULL);
		child_xs_obj = INT2PTR(xs_ea_object_t *, SvIV(perl_obj));
		PERL_ASSERT(child_xs_obj->ea_obj != NULL);

		/* Free any existing object contents. */
		if (ea_obj->eo_item.ei_object != NULL) {
			ea_free(ea_obj->eo_item.ei_object,
			    ea_obj->eo_item.ei_size);
			ea_obj->eo_item.ei_object = NULL;
			ea_obj->eo_item.ei_size = 0;
		}

		/*  Pack the object. */
		while (1) {
			/* Use the last buffer size as a best guess. */
			if (last_bufsz != 0) {
				ea_obj->eo_item.ei_object =
				    ea_alloc(last_bufsz);
				PERL_ASSERT(ea_obj->eo_item.ei_object != NULL);
			} else {
				ea_obj->eo_item.ei_object = NULL;
			}

			/*
			 * Pack the object.  If the buffer is too small,
			 * we will go around again with the correct size.
			 * If unsucessful, we will bail.
			 */
			if ((bufsz = ea_pack_object(child_xs_obj->ea_obj,
			    ea_obj->eo_item.ei_object, last_bufsz)) == -1) {
				ea_free(ea_obj->eo_item.ei_object, last_bufsz);
				ea_obj->eo_item.ei_object = NULL;
				return (NULL);
			} else if (bufsz > last_bufsz) {
				ea_free(ea_obj->eo_item.ei_object, last_bufsz);
				last_bufsz = bufsz;
				continue;
			} else {
				ea_obj->eo_item.ei_size = bufsz;
				break;
			}
		}

	/* Deal with Groups. */
	} else if (IS_GROUP(xs_obj)) {