/* $NetBSD: prop_object.c,v 1.12 2006/10/19 10:10:35 he Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* _prop_object_externalize_append_char --
* Append a single character to the externalize buffer.
*/
boolean_t
_prop_object_externalize_append_char(
struct _prop_object_externalize_context *ctx, unsigned char c)
{
/* Buffer is always freed by the caller. */
_PROP_FREE(ctx, M_TEMP);
}
#if !defined(_KERNEL) && !defined(_STANDALONE)
/*
* _prop_object_externalize_file_dirname --
* dirname(3), basically. We have to roll our own because the
* system dirname(3) isn't reentrant.
*/
static void
_prop_object_externalize_file_dirname(const char *path, char *result)
{
const char *lastp;
size_t len;
/*
* If `path' is a NULL pointer or points to an empty string,
* return ".".
*/
if (path == NULL || *path == '\0')
goto singledot;
/* Terminate path at the last occurrence of '/'. */
do {
if (*lastp == '/') {
/* Strip trailing slashes, if any. */
while (lastp != path && *lastp == '/')
lastp--;
/* ...and copy the result into the result buffer. */
len = (lastp - path) + 1 /* last char */;
if (len > (PATH_MAX - 1))
len = PATH_MAX - 1;
/*
* _prop_object_externalize_write_file --
* Write an externalized dictionary to the specified file.
* The file is written atomically from the caller's perspective,
* and the mode set to 0666 modified by the caller's umask.
*/
boolean_t
_prop_object_externalize_write_file(const char *fname, const char *xml,
size_t len)
{
char tname[PATH_MAX];
int fd;
int save_errno;
/*
* Get the directory name where the file is to be written
* and create the temporary file.
*
* We don't use mkstemp() because mkstemp() always creates the
* file with mode 0600. We do, however, use mktemp() safely.
*/
again:
_prop_object_externalize_file_dirname(fname, tname);
if (strlcat(tname, "/.plistXXXXXX", sizeof(tname)) >= sizeof(tname)) {
errno = ENAMETOOLONG;
return (FALSE);
}
if (mktemp(tname) == NULL)
return (FALSE);
if ((fd = open(tname, O_CREAT|O_RDWR|O_EXCL, 0666)) == -1) {
if (errno == EEXIST)
goto again;
return (FALSE);
}
if (write(fd, xml, len) != (ssize_t)len)
goto bad;
/*
* If the file length is an integral number of pages, then we
* need to map a guard page at the end in order to provide the
* necessary NUL-termination of the buffer.
*/
if ((sb.st_size & pgmask) == 0)
need_guard = TRUE;
/*
* Retain / release serialization --
*
* Eventually we would like to use atomic operations. But until we have
* an MI API for them that is common to userland and the kernel, we will
* use a lock instead.
*
* We use a single global mutex for all serialization. In the kernel, because
* we are still under a biglock, this will basically never contend (properties
* cannot be manipulated at interrupt level). In userland, this will cost
* nothing for single-threaded programs. For multi-threaded programs, there
* could be contention, but it probably won't cost that much unless the program
* makes heavy use of property lists.
*/
_PROP_MUTEX_DECL_STATIC(_prop_refcnt_mutex)
#define _PROP_REFCNT_LOCK() _PROP_MUTEX_LOCK(_prop_refcnt_mutex)
#define _PROP_REFCNT_UNLOCK() _PROP_MUTEX_UNLOCK(_prop_refcnt_mutex)
/*
* prop_object_retain --
* Increment the reference count on an object.
*/
void
prop_object_retain(prop_object_t obj)
{
struct _prop_object *po = obj;
uint32_t ocnt;
/*
* prop_object_release --
* Decrement the reference count on an object.
*
* Free the object if we are releasing the final
* reference.
*/
void
prop_object_release(prop_object_t obj)
{
struct _prop_object *po = obj;
uint32_t ocnt;
/*
* prop_object_iterator_next --
* Return the next item during an iteration.
*/
prop_object_t
prop_object_iterator_next(prop_object_iterator_t pi)
{
return ((*pi->pi_next_object)(pi));
}
/*
* prop_object_iterator_reset --
* Reset the iterator to the first object so as to restart
* iteration.
*/
void
prop_object_iterator_reset(prop_object_iterator_t pi)
{