예제 #1
0
파일: json.c 프로젝트: kaduk/heimdal
static heim_object_t
parse_value(struct parse_ctx *ctx)
{
    size_t len;
    heim_object_t o;

    if (white_spaces(ctx))
	return NULL;

    if (*ctx->p == '"') {
	return parse_string(ctx);
    } else if (*ctx->p == '{') {
	if (ctx->depth-- == 1) {
	    ctx->error = heim_error_create(EINVAL, "JSON object too deep");
	    return NULL;
	}
	o = parse_dict(ctx);
	ctx->depth++;
	return o;
    } else if (*ctx->p == '[') {
	if (ctx->depth-- == 1) {
	    ctx->error = heim_error_create(EINVAL, "JSON object too deep");
	    return NULL;
	}
	o = parse_array(ctx);
	ctx->depth++;
	return o;
    } else if (is_number(*ctx->p) || *ctx->p == '-') {
	return parse_number(ctx);
    }

    len = ctx->pend - ctx->p;

    if ((ctx->flags & HEIM_JSON_F_NO_C_NULL) == 0 &&
	len >= 6 && memcmp(ctx->p, "<NULL>", 6) == 0) {
	ctx->p += 6;
	return heim_null_create();
    } else if (len >= 4 && memcmp(ctx->p, "null", 4) == 0) {
	ctx->p += 4;
	return heim_null_create();
    } else if (len >= 4 && strncasecmp((char *)ctx->p, "true", 4) == 0) {
	ctx->p += 4;
	return heim_bool_create(1);
    } else if (len >= 5 && strncasecmp((char *)ctx->p, "false", 5) == 0) {
	ctx->p += 5;
	return heim_bool_create(0);
    }

    ctx->error = heim_error_create(EINVAL, "unknown char %c at %lu line %lu",
				   (char)*ctx->p, 
				   (unsigned long)(ctx->p - ctx->pstart),
				   ctx->lineno);
    return NULL;
}
예제 #2
0
static heim_string_t
parse_string(struct parse_ctx *ctx)
{
    const uint8_t *start;
    int quote = 0;

    heim_assert(*ctx->p == '"', "string doesnt' start with \"");
    start = ++ctx->p;

    while (ctx->p < ctx->pend) {
	if (*ctx->p == '\n') {
	    ctx->lineno++;
	} else if (*ctx->p == '\\') {
	    if (ctx->p + 1 == ctx->pend)
		goto out;
	    ctx->p += 1;
	    quote = 1;
	} else if (*ctx->p == '"') {
	    heim_object_t o;

	    if (quote) {
		char *p0, *p;
		p = p0 = malloc(ctx->p - start);
		if (p == NULL)
		    goto out;
		while (start < ctx->p) {
		    if (*start == '\\') {
			start++;
			/* XXX validate qouted char */
		    }
		    *p++ = *start++;
		}
		o = heim_string_create_with_bytes(p0, p - p0);
		free(p0);
	    } else {
		o = heim_string_create_with_bytes(start, ctx->p - start);
	    }
	    ctx->p += 1;

	    return o;
	}    
	ctx->p += 1;
    }
    out:
    ctx->error = heim_error_create(EINVAL, "ran out of string");
    return NULL;
}
예제 #3
0
파일: db.c 프로젝트: InvLim/heimdal
/**
 * Clone (duplicate) an open DB handle.
 *
 * This is useful for multi-threaded applications.  Applications must
 * synchronize access to any given DB handle.
 *
 * Returns EBUSY if there is an open transaction for the input db.
 *
 * @param db      Open DB handle
 * @param error   Output error object
 *
 * @return a DB handle
 *
 * @addtogroup heimbase
 */
heim_db_t
heim_db_clone(heim_db_t db, heim_error_t *error)
{
    heim_db_t result;
    int ret;

    if (heim_get_tid(db) != HEIM_TID_DB)
	heim_abort("Expected a database");
    if (db->in_transaction)
	heim_abort("DB handle is busy");

    if (db->plug->clonef == NULL) {
	return heim_db_create(heim_string_get_utf8(db->dbtype),
			      heim_string_get_utf8(db->dbname),
			      db->options, error);
    }

    result = _heim_alloc_object(&db_object, sizeof(*result));
    if (result == NULL) {
	if (error)
	    *error = heim_error_create_enomem();
	return NULL;
    }

    result->set_keys = NULL;
    result->del_keys = NULL;
    ret = db->plug->clonef(db->db_data, &result->db_data, error);
    if (ret) {
	heim_release(result);
	if (error && !*error)
	    *error = heim_error_create(ENOENT,
				       N_("Could not re-open DB while cloning", ""));
	return NULL;
    }
    db->db_data = NULL;
    return result;
}
예제 #4
0
static heim_object_t
parse_value(struct parse_ctx *ctx)
{
    size_t len;

    if (white_spaces(ctx))
	return NULL;

    if (*ctx->p == '"') {
	return parse_string(ctx);
    } else if (*ctx->p == '{') {
	return parse_dict(ctx);
    } else if (*ctx->p == '[') {
	return parse_array(ctx);
    } else if (is_number(*ctx->p) || *ctx->p == '-') {
	return parse_number(ctx);
    }

    len = ctx->pend - ctx->p;

    if (len >= 4 && memcmp(ctx->p, "null", 4) == 0) {
	ctx->p += 4;
	return heim_null_create();
    } else if (len >= 4 && strncasecmp((char *)ctx->p, "true", 4) == 0) {
	ctx->p += 4;
	return heim_bool_create(1);
    } else if (len >= 5 && strncasecmp((char *)ctx->p, "false", 5) == 0) {
	ctx->p += 5;
	return heim_bool_create(0);
    }

    ctx->error = heim_error_create(EINVAL, "unknown char %c at %lu line %lu",
				   (char)*ctx->p, 
				   (unsigned long)(ctx->p - ctx->pstart),
				   ctx->lineno);
    return NULL;
}
예제 #5
0
파일: db.c 프로젝트: InvLim/heimdal
/**
 * Open a database of the given dbtype.
 *
 * Database type names can be composed of one or more pseudo-DB types
 * and one concrete DB type joined with a '+' between each.  For
 * example: "transaction+bdb" might be a Berkeley DB with a layer above
 * that provides transactions.
 *
 * Options may be provided via a dict (an associative array).  Existing
 * options include:
 *
 *  - "create", with any value (create if DB doesn't exist)
 *  - "exclusive", with any value (exclusive create)
 *  - "truncate", with any value (truncate the DB)
 *  - "read-only", with any value (disallow writes)
 *  - "sync", with any value (make transactions durable)
 *  - "journal-name", with a string value naming a journal file name
 *
 * @param dbtype  Name of DB type
 * @param dbname  Name of DB (likely a file path)
 * @param options Options dict
 * @param db      Output open DB handle
 * @param error   Output error  object
 *
 * @return a DB handle
 *
 * @addtogroup heimbase
 */
heim_db_t
heim_db_create(const char *dbtype, const char *dbname,
	       heim_dict_t options, heim_error_t *error)
{
    heim_string_t s;
    char *p;
    db_plugin plug;
    heim_db_t db;
    int ret = 0;

    if (options == NULL) {
	options = heim_dict_create(11);
	if (options == NULL) {
	    if (error)
		*error = heim_error_create_enomem();
	    return NULL;
	}
    } else {
	(void) heim_retain(options);
    }

    if (db_plugins == NULL) {
	heim_release(options);
	return NULL;
    }

    if (dbtype == NULL || *dbtype == '\0') {
	struct dbtype_iter iter_ctx = { NULL, dbname, options, error};

	/* Try all dbtypes */
	heim_dict_iterate_f(db_plugins, &iter_ctx, dbtype_iter2create_f);
	heim_release(options);
	return iter_ctx.db;
    } else if (strstr(dbtype, "json")) {
	(void) heim_db_register(dbtype, NULL, &json_dbt);
    }

    /*
     * Allow for dbtypes that are composed from pseudo-dbtypes chained
     * to a real DB type with '+'.  For example a pseudo-dbtype might
     * add locking, transactions, transcoding of values, ...
     */
    p = strchr(dbtype, '+');
    if (p != NULL)
	s = heim_string_create_with_bytes(dbtype, p - dbtype);
    else
	s = heim_string_create(dbtype);
    if (s == NULL) {
	heim_release(options);
	return NULL;
    }

    HEIMDAL_MUTEX_lock(&db_type_mutex);
    plug = heim_dict_get_value(db_plugins, s);
    HEIMDAL_MUTEX_unlock(&db_type_mutex);
    heim_release(s);
    if (plug == NULL) {
	if (error)
	    *error = heim_error_create(ENOENT,
				       N_("Heimdal DB plugin not found: %s", ""),
				       dbtype);
	heim_release(options);
	return NULL;
    }

    db = _heim_alloc_object(&db_object, sizeof(*db));
    if (db == NULL) {
	heim_release(options);
	return NULL;
    }

    db->in_transaction = 0;
    db->ro_tx = 0;
    db->set_keys = NULL;
    db->del_keys = NULL;
    db->plug = plug;
    db->options = options;

    ret = plug->openf(plug->data, dbtype, dbname, options, &db->db_data, error);
    if (ret) {
	heim_release(db);
	if (error && *error == NULL)
	    *error = heim_error_create(ENOENT,
				       N_("Heimdal DB could not be opened: %s", ""),
				       dbname);
	return NULL;
    }

    ret = db_replay_log(db, error);
    if (ret) {
	heim_release(db);
	return NULL;
    }

    if (plug->clonef == NULL) {
	db->dbtype = heim_string_create(dbtype);
	db->dbname = heim_string_create(dbname);

	if (!db->dbtype || ! db->dbname) {
	    heim_release(db);
	    if (error)
		*error = heim_error_create_enomem();
	    return NULL;
	}
    }

    return db;
}
예제 #6
0
파일: db.c 프로젝트: InvLim/heimdal
static int
open_file(const char *dbname, int for_write, int excl, int *fd_out, heim_error_t *error)
{
#ifdef WIN32
    HANDLE hFile;
    int ret = 0;

    if (fd_out)
	*fd_out = -1;

    if (for_write)
	hFile = CreateFile(dbname, GENERIC_WRITE | GENERIC_READ, 0,
			   NULL, /* we'll close as soon as we read */
			   CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    else
	hFile = CreateFile(dbname, GENERIC_READ, FILE_SHARE_READ,
			   NULL, /* we'll close as soon as we read */
			   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
	ret = GetLastError();
	_set_errno(ret); /* CreateFile() does not set errno */
	goto err;
    }
    if (fd_out == NULL) {
	(void) CloseHandle(hFile);
	return 0;
    }

    *fd_out = _open_osfhandle((intptr_t) hFile, 0);
    if (*fd_out < 0) {
	ret = errno;
	(void) CloseHandle(hFile);
	goto err;
    }

    /* No need to lock given share deny mode */
    return 0;

err:
    if (error != NULL) {
	char *s = NULL;
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
		      0, ret, 0, (LPTSTR) &s, 0, NULL);
	*error = heim_error_create(ret, N_("Could not open JSON file %s: %s", ""),
				   dbname, s ? s : "<error formatting error>");
	LocalFree(s);
    }
    return ret;
#else
    int ret = 0;
    int fd;

    if (fd_out)
	*fd_out = -1;

    if (for_write && excl)
	fd = open(dbname, O_CREAT | O_EXCL | O_WRONLY, 0600);
    else if (for_write)
	fd = open(dbname, O_CREAT | O_TRUNC | O_WRONLY, 0600);
    else
	fd = open(dbname, O_RDONLY);
    if (fd < 0) {
	if (error != NULL)
	    *error = heim_error_create(ret, N_("Could not open JSON file %s: %s", ""),
				       dbname, strerror(errno));
	return errno;
    }

    if (fd_out == NULL) {
	(void) close(fd);
	return 0;
    }

    ret = flock(fd, for_write ? LOCK_EX : LOCK_SH);
    if (ret == -1) {
	/* Note that we if O_EXCL we're leaving the [lock] file around */
	(void) close(fd);
	return HEIM_ERROR(error, errno,
			  (errno, N_("Could not lock JSON file %s: %s", ""),
			   dbname, strerror(errno)));
    }

    *fd_out = fd;
    
    return 0;
#endif
}
예제 #7
0
파일: json.c 프로젝트: kaduk/heimdal
static int
parse_pair(heim_dict_t dict, struct parse_ctx *ctx)
{
    heim_string_t key;
    heim_object_t value;

    if (white_spaces(ctx))
	return -1;

    if (*ctx->p == '}') {
	ctx->p++;
	return 0;
    }

    if (ctx->flags & HEIM_JSON_F_STRICT_DICT)
	/* JSON allows only string keys */
	key = parse_string(ctx);
    else
	/* heim_dict_t allows any heim_object_t as key */
	key = parse_value(ctx);
    if (key == NULL)
	/* Even heim_dict_t does not allow C NULLs as keys though! */
	return -1;

    if (white_spaces(ctx)) {
	heim_release(key);
	return -1;
    }

    if (*ctx->p != ':') {
	heim_release(key);
	return -1;
    }

    ctx->p += 1; /* safe because we call white_spaces() next */

    if (white_spaces(ctx)) {
	heim_release(key);
	return -1;
    }

    value = parse_value(ctx);
    if (value == NULL &&
	(ctx->error != NULL || (ctx->flags & HEIM_JSON_F_NO_C_NULL))) {
	if (ctx->error == NULL)
	    ctx->error = heim_error_create(EINVAL, "Invalid JSON encoding");
	heim_release(key);
	return -1;
    }
    heim_dict_set_value(dict, key, value);
    heim_release(key);
    heim_release(value);

    if (white_spaces(ctx))
	return -1;

    if (*ctx->p == '}') {
	/*
	 * Return 1 but don't consume the '}' so we can count the one
	 * pair in a one-pair dict
	 */
	return 1;
    } else if (*ctx->p == ',') {
	ctx->p++;
	return 1;
    }
    return -1;
}
예제 #8
0
파일: json.c 프로젝트: kaduk/heimdal
static heim_string_t
parse_string(struct parse_ctx *ctx)
{
    const uint8_t *start;
    int quote = 0;

    if (ctx->flags & HEIM_JSON_F_STRICT_STRINGS) {
	ctx->error = heim_error_create(EINVAL, "Strict JSON string encoding "
				       "not yet supported");
	return NULL;
    }

    if (*ctx->p != '"') {
	ctx->error = heim_error_create(EINVAL, "Expected a JSON string but "
				       "found something else at line %lu",
				       ctx->lineno);
	return NULL;
    }
    start = ++ctx->p;

    while (ctx->p < ctx->pend) {
	if (*ctx->p == '\n') {
	    ctx->lineno++;
	} else if (*ctx->p == '\\') {
	    if (ctx->p + 1 == ctx->pend)
		goto out;
	    ctx->p++;
	    quote = 1;
	} else if (*ctx->p == '"') {
	    heim_object_t o;

	    if (quote) {
		char *p0, *p;
		p = p0 = malloc(ctx->p - start);
		if (p == NULL)
		    goto out;
		while (start < ctx->p) {
		    if (*start == '\\') {
			start++;
			/* XXX validate quoted char */
		    }
		    *p++ = *start++;
		}
		o = heim_string_create_with_bytes(p0, p - p0);
		free(p0);
	    } else {
		o = heim_string_create_with_bytes(start, ctx->p - start);
		if (o == NULL) {
		    ctx->error = heim_error_create_enomem();
		    return NULL;
		}

		/* If we can decode as base64, then let's */
		if (ctx->flags & HEIM_JSON_F_TRY_DECODE_DATA) {
		    void *buf;
		    size_t len;
		    const char *s;

		    s = heim_string_get_utf8(o);
		    len = strlen(s);

		    if (len >= 4 && strspn(s, base64_chars) >= len - 2) {
			buf = malloc(len);
			if (buf == NULL) {
			    heim_release(o);
			    ctx->error = heim_error_create_enomem();
			    return NULL;
			}
			len = base64_decode(s, buf);
			if (len == -1) {
			    free(buf);
			    return o;
			}
			heim_release(o);
			o = heim_data_ref_create(buf, len, free);
		    }
		}
	    }
	    ctx->p += 1;

	    return o;
	}
	ctx->p += 1;
    }
    out:
    ctx->error = heim_error_create(EINVAL, "ran out of string");
    return NULL;
}