/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 1.0 (the 'License'). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License." * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include void serialize_32(u_int32_t v, char **p) { u_int32_t n; n = htonl(v); memmove(*p, &n, 4); *p += 4; } /* serialize a record into a machine-independent string of bytes */ dsdata * dsrecord_to_dsdata(dsrecord *r) { u_int32_t i, len, type, attrx, valx; dsdata *d; char *p; if (r == NULL) return NULL; len = 0; /* dsid */ len += 4; /* serial */ len += 4; /* vers */ len += 4; /* super */ len += 4; /* sub_count */ len += 4; /* sub */ len += (4 * r->sub_count); /* count */ len += 4; /* attributes */ for (attrx = 0; attrx < r->count; attrx++) { /* key length + type + data */ len += (4 + 4 + r->attribute[attrx]->key->length); /* count */ len += 4; /* values */ for (valx = 0; valx < r->attribute[attrx]->count; valx++) { /* value length + type + data */ len += (4 + 4 + r->attribute[attrx]->value[valx]->length); } } /* meta_count */ len += 4; /* meta attributes */ for (attrx = 0; attrx < r->meta_count; attrx++) { /* key length + type + data */ len += (4 + 4 + r->meta_attribute[attrx]->key->length); /* count */ len += 4; /* values */ for (valx = 0; valx < r->meta_attribute[attrx]->count; valx++) { /* value length + type + data */ len += (4 + 4 + r->meta_attribute[attrx]->value[valx]->length); } } d = dsdata_alloc(len); d->retain = 1; d->type = DataTypeDSRecord; p = d->data; /* record id */ serialize_32(r->dsid, &p); /* record serial number */ serialize_32(r->serial, &p); /* datastore version */ serialize_32(r->vers, &p); /* super */ serialize_32(r->super, &p); /* sub_count */ serialize_32(r->sub_count, &p); /* sub */ for (i = 0; i < r->sub_count; i++) { serialize_32(r->sub[i], &p); } /* count */ serialize_32(r->count, &p); /* attributes */ for (attrx = 0; attrx < r->count; attrx++) { /* key type */ type = r->attribute[attrx]->key->type; serialize_32(type, &p); /* key length */ len = r->attribute[attrx]->key->length; serialize_32(len, &p); /* key data */ memmove(p, r->attribute[attrx]->key->data, len); p += len; /* count */ serialize_32(r->attribute[attrx]->count, &p); /* values */ for (valx = 0; valx < r->attribute[attrx]->count; valx++) { /* value type */ type = r->attribute[attrx]->value[valx]->type; serialize_32(type, &p); /* value length */ len = r->attribute[attrx]->value[valx]->length; serialize_32(len, &p); /* value data */ memmove(p, r->attribute[attrx]->value[valx]->data, len); p += len; } } /* meta_count */ serialize_32(r->meta_count, &p); /* meta_attributes */ for (attrx = 0; attrx < r->meta_count; attrx++) { /* key type */ type = r->meta_attribute[attrx]->key->type; serialize_32(type, &p); /* key length */ len = r->meta_attribute[attrx]->key->length; serialize_32(len, &p); /* key data */ memmove(p, r->meta_attribute[attrx]->key->data, len); p += len; /* count */ serialize_32(r->meta_attribute[attrx]->count, &p); /* values */ for (valx = 0; valx < r->meta_attribute[attrx]->count; valx++) { /* value type */ type = r->meta_attribute[attrx]->value[valx]->type; serialize_32(type, &p); /* value length */ len = r->meta_attribute[attrx]->value[valx]->length; serialize_32(len, &p); /* value data */ memmove(p, r->meta_attribute[attrx]->value[valx]->data, len); p += len; } } return d; } u_int32_t deserialize_32(char **p) { u_int32_t n, t; memmove(&t, *p, 4); *p += 4; n = ntohl(t); return n; } dsdata * deserialize_dsdata(char **p) { dsdata *udata; u_int32_t t, l; t = deserialize_32(p); l = deserialize_32(p); udata = dsdata_alloc(l); udata->type = t; udata->retain = 1; if (udata->length > 0) memmove(udata->data, *p, udata->length); *p += udata->length; return udata; } dsrecord * dsdata_to_dsrecord(dsdata *d) { dsrecord *r; char *p; u_int32_t i, len, attrx, valx; if (d == NULL) return NULL; if (d->type != DataTypeDSRecord) return NULL; r = (dsrecord *)malloc(sizeof(dsrecord)); r->retain = 1; p = d->data; r->dsid = deserialize_32(&p); r->serial = deserialize_32(&p); r->vers = deserialize_32(&p); r->super = deserialize_32(&p); r->sub_count = deserialize_32(&p); if (r->sub_count > 0) r->sub = (u_int32_t *)malloc(r->sub_count * sizeof(u_int32_t)); else r->sub = NULL; for (i = 0; i < r->sub_count; i++) { r->sub[i] = deserialize_32(&p); } r->count = deserialize_32(&p); if (r->count > 0) r->attribute = (dsattribute **)malloc(r->count * sizeof(dsattribute *)); else r->attribute = NULL; for (attrx = 0; attrx < r->count; attrx++) { r->attribute[attrx] = dsattribute_alloc(); r->attribute[attrx]->retain = 1; r->attribute[attrx]->key = deserialize_dsdata(&p); len = deserialize_32(&p); r->attribute[attrx]->count = len; if (len > 0) r->attribute[attrx]->value = (dsdata **)malloc(len * sizeof(dsdata *)); else r->attribute[attrx]->value = NULL; for (valx = 0; valx < r->attribute[attrx]->count; valx++) r->attribute[attrx]->value[valx] = deserialize_dsdata(&p); } r->meta_count = deserialize_32(&p); if (r->meta_count > 0) r->meta_attribute = (dsattribute **)malloc(r->meta_count * sizeof(dsattribute *)); else r->meta_attribute = NULL; for (attrx = 0; attrx < r->meta_count; attrx++) { r->meta_attribute[attrx] = dsattribute_alloc(); r->meta_attribute[attrx]->retain = 1; r->meta_attribute[attrx]->key = deserialize_dsdata(&p); len = deserialize_32(&p); r->meta_attribute[attrx]->count = len; if (len > 0) r->meta_attribute[attrx]->value = (dsdata **)malloc(len * sizeof(dsdata *)); else r->meta_attribute[attrx]->value = NULL; for (valx = 0; valx < r->meta_attribute[attrx]->count; valx++) r->meta_attribute[attrx]->value[valx] = deserialize_dsdata(&p); } r->index = NULL; r->next = NULL; return r; } /* * Performance hack to get a record's vital stats (dsid, vers, serial, and super) */ dsstatus dsrecord_fstats(FILE *f, u_int32_t *dsid, u_int32_t *vers, u_int32_t *serial, u_int32_t *super) { int n; u_int32_t x; if (dsid != NULL) *dsid = IndexNull; if (vers != NULL) *vers = IndexNull; if (serial != NULL) *serial = IndexNull; if (super != NULL) *super = IndexNull; if (f == NULL) return DSStatusInvalidStore; /* dsdata type */ n = fread(&x, sizeof(u_int32_t), 1, f); if (n != 1) return DSStatusReadFailed; n = ntohl(x); if (n != DataTypeDSRecord) return DSStatusInvalidRecord; /* dsdata length */ n = fread(&x, sizeof(u_int32_t), 1, f); if (n != 1) return DSStatusReadFailed; /* dsrecord dsid */ n = fread(&x, sizeof(u_int32_t), 1, f); if (n != 1) return DSStatusReadFailed; if (dsid != NULL) *dsid = ntohl(x); /* dsrecord serial */ n = fread(&x, sizeof(u_int32_t), 1, f); if (n != 1) return DSStatusReadFailed; if (serial != NULL) *serial = ntohl(x); /* dsrecord vers */ n = fread(&x, sizeof(u_int32_t), 1, f); if (n != 1) return DSStatusReadFailed; if (vers != NULL) *vers = ntohl(x); /* dsrecord super */ n = fread(&x, sizeof(u_int32_t), 1, f); if (n != 1) return DSStatusReadFailed; if (super != NULL) *super = ntohl(x); return DSStatusOK; } dsrecord * dsrecord_new(void) { dsrecord *r; r = (dsrecord *)malloc(sizeof(dsrecord)); r->retain = 1; r->dsid = -1; r->serial = 0; r->vers = -1; r->super = -1; r->sub_count = 0; r->sub = NULL; r->count = 0; r->attribute = NULL; r->meta_count = 0; r->meta_attribute = NULL; r->index = NULL; r->next = NULL; return r; } dsrecord * dsrecord_retain(dsrecord *r) { if (r == NULL) return NULL; r->retain++; return r; } static dsrecord * dsrecord_release_worker(dsrecord *r) { u_int32_t i; dsrecord *n; if (r == NULL) return NULL; r->retain--; if (r->retain > 0) return NULL; if (r->sub_count > 0) free(r->sub); for (i = 0; i < r->count; i++) dsattribute_release(r->attribute[i]); if (r->count > 0) free(r->attribute); for (i = 0; i < r->meta_count; i++) dsattribute_release(r->meta_attribute[i]); if (r->meta_count > 0) free(r->meta_attribute); if (r->index != NULL) dsindex_free(r->index); n = r->next; free(r); return n; } void dsrecord_release(dsrecord *r) { dsrecord *n; n = r; while (n != NULL) { n = dsrecord_release_worker(n); } } dsrecord * dsrecord_read(char *filename) { dsdata *d; dsrecord *r; d = dsdata_read(filename); r = dsdata_to_dsrecord(d); dsdata_release(d); return r; } dsrecord * dsrecord_fread(FILE *f) { dsdata *d; dsrecord *r; d = dsdata_fread(f); r = dsdata_to_dsrecord(d); dsdata_release(d); return r; } dsstatus dsrecord_write(dsrecord *r, char *filename) { dsdata *d; dsstatus ds; d = dsrecord_to_dsdata(r); ds = dsdata_write(d, filename); dsdata_release(d); return ds; } dsstatus dsrecord_fwrite(dsrecord *r, FILE *f) { dsdata *d; dsstatus ds; d = dsrecord_to_dsdata (r); ds = dsdata_fwrite(d, f); dsdata_release(d); return ds; } dsrecord * dsrecord_copy(dsrecord *r) { dsdata *d; dsrecord *x; if (r == NULL) return NULL; d = dsrecord_to_dsdata(r); if (d == NULL) return NULL; x = dsdata_to_dsrecord(d); dsdata_release(d); x->dsid = -1; return x; } u_int32_t dsrecord_has_sub(dsrecord *r, u_int32_t c) { u_int32_t i, len; if (r == NULL) return 0; len = r->sub_count; for (i = 0; i < len; i++) if (r->sub[i] == c) return 1; return 0; } void dsrecord_append_sub(dsrecord *r, u_int32_t c) { u_int32_t i, len; if (r == NULL) return; if (c == 0) return; if (c == r->dsid) return; if (c == r->super) return; len = r->sub_count; for (i = 0; i < len; i++) if (r->sub[i] == c) return; r->sub_count++; if (len == 0) r->sub = (u_int32_t *)malloc(sizeof(u_int32_t)); else r->sub = (u_int32_t *)realloc(r->sub, r->sub_count * sizeof(u_int32_t)); r->sub[len] = c; } void dsrecord_remove_sub(dsrecord *r, u_int32_t c) { u_int32_t i; if (r == NULL) return; for (i = 0; i < r->sub_count; i++) if (r->sub[i] == c) break; if (i >= r->sub_count) return; if (r->sub_count == 1) { free(r->sub); r->sub = NULL; r->sub_count = 0; return; } for (i += 1; i < r->sub_count; i++) r->sub[i - 1] = r->sub[i]; r->sub_count--; r->sub = (u_int32_t *)realloc(r->sub, r->sub_count * sizeof(u_int32_t)); } void dsrecord_merge_attribute(dsrecord *r, dsattribute *a, u_int32_t asel) { u_int32_t i, x, len, merge; dsattribute **attribute; if (r == NULL) return; if (a == NULL) return; attribute = r->attribute; len = r->count; if (asel == SELECT_META_ATTRIBUTE) { attribute = r->meta_attribute; len = r->meta_count; } merge = 0; x = 0; for (i = 0; i < len; i++) { if (dsattribute_equal(attribute[i], a)) return; if (dsdata_equal(attribute[i]->key, a->key)) { x = i; merge = 1; break; } } if (merge == 1) { for (i = 0; i < a->count; i++) dsattribute_merge(attribute[x], a->value[i]); return; } dsrecord_append_attribute(r, a, asel); } void dsrecord_insert_attribute(dsrecord *r, dsattribute *a, u_int32_t where, u_int32_t asel) { u_int32_t len, x, i; if (r == NULL) return; if (a == NULL) return; if (asel == SELECT_ATTRIBUTE) { len = r->count; r->count++; if (len == 0) r->attribute = (dsattribute **)malloc(sizeof(dsattribute *)); else r->attribute = (dsattribute **)realloc(r->attribute, r->count * sizeof(dsattribute *)); x = where; if (x > len) x = len; for (i = len; i > x; i--) r->attribute[i] = r->attribute[i-1]; r->attribute[x] = dsattribute_retain(a); } else { len = r->meta_count; r->meta_count++; if (len == 0) r->meta_attribute = (dsattribute **)malloc(sizeof(dsattribute *)); else r->meta_attribute = (dsattribute **)realloc(r->meta_attribute, r->meta_count * sizeof(dsattribute *)); x = where; if (x > len) x = len; for (i = len; i > x; i--) r->meta_attribute[i] = r->meta_attribute[i-1]; r->meta_attribute[x] = dsattribute_retain(a); } } void dsrecord_append_attribute(dsrecord *r, dsattribute *a, u_int32_t asel) { u_int32_t len; if (r == NULL) return; if (a == NULL) return; if (asel == SELECT_ATTRIBUTE) { len = r->count; r->count++; if (len == 0) r->attribute = (dsattribute **)malloc(sizeof(dsattribute *)); else r->attribute = (dsattribute **)realloc(r->attribute, r->count * sizeof(dsattribute *)); r->attribute[len] = dsattribute_retain(a); } else { len = r->meta_count; r->meta_count++; if (len == 0) r->meta_attribute = (dsattribute **)malloc(sizeof(dsattribute *)); else r->meta_attribute = (dsattribute **)realloc(r->meta_attribute, r->meta_count * sizeof(dsattribute *)); r->meta_attribute[len] = dsattribute_retain(a); } } static void dsrecord_remove_attribute_index(dsrecord *r, u_int32_t x, u_int32_t asel) { u_int32_t i, len; dsattribute **attribute; if (r == NULL) return; len = r->count; attribute = r->attribute; if (asel == SELECT_META_ATTRIBUTE) { len = r->meta_count; attribute = r->meta_attribute; } if (x >= len) return; dsattribute_release(attribute[x]); if (len == 1) { if (asel == SELECT_ATTRIBUTE) { free(r->attribute); r->attribute = NULL; r->count = 0; } else { free(r->meta_attribute); r->meta_attribute = NULL; r->meta_count = 0; } return; } for (i = x + 1; i < len; i++) attribute[i - 1] = attribute[i]; if (asel == SELECT_ATTRIBUTE) { r->count--; r->attribute = (dsattribute **)realloc(r->attribute, r->count * sizeof(dsattribute *)); } else { r->meta_count--; r->meta_attribute = (dsattribute **)realloc(r->meta_attribute, r->meta_count * sizeof(dsattribute *)); } } void dsrecord_remove_attribute(dsrecord *r, dsattribute *a, u_int32_t asel) { u_int32_t i, len; dsattribute **attribute; if (r == NULL) return; if (a == NULL) return; attribute = r->attribute; len = r->count; if (asel == SELECT_META_ATTRIBUTE) { attribute = r->meta_attribute; len = r->meta_count; } for (i = 0; i < len; i++) if (dsattribute_equal(attribute[i], a)) break; if (i >= len) return; dsrecord_remove_attribute_index(r, i, asel); } dsattribute * dsrecord_attribute(dsrecord *r, dsdata *k, u_int32_t asel) { u_int32_t i, len; dsattribute **attribute; dsattribute *a; if (r == NULL) return NULL; if (k == NULL) return NULL; attribute = r->attribute; len = r->count; if (asel == SELECT_META_ATTRIBUTE) { attribute = r->meta_attribute; len = r->meta_count; } for (i = 0; i < len; i++) { if (dsdata_equal(attribute[i]->key, k)) { a = attribute[i]; return dsattribute_retain(a); } } return NULL; } void dsrecord_remove_key(dsrecord *r, dsdata *k, u_int32_t asel) { u_int32_t i, len; dsattribute **attribute; if (r == NULL) return; if (k == NULL) return; attribute = r->attribute; len = r->count; if (asel == SELECT_META_ATTRIBUTE) { attribute = r->meta_attribute; len = r->meta_count; } for (i = 0; i < len; i++) { if (dsdata_equal(attribute[i]->key, k)) break; } if (i >= len) return; dsrecord_remove_attribute_index(r, i, asel); } /* * Find a key or meta key and return its index. */ u_int32_t dsrecord_attribute_index(dsrecord *r, dsdata *key, u_int32_t asel) { u_int32_t i; if (asel == SELECT_ATTRIBUTE) { for (i = 0; i < r->count; i++) if (dsdata_equal(r->attribute[i]->key, key)) return i; } else { for (i = 0; i < r->meta_count; i++) if (dsdata_equal(r->meta_attribute[i]->key, key)) return i; } return IndexNull; } /* * Test a record for given key and value. * Returns 1 for match, 0 for no match. * If value is NULL, tests for presence of key. * If key is NULL, tests all keys for this value. * If key and value are both NULL, returns 1. */ int dsrecord_match_key_val(dsrecord *r, dsdata *k, dsdata *v, u_int32_t asel) { u_int32_t i, len; dsattribute **attribute; if (r == NULL) return 0; if ((k == NULL) && (v == NULL)) return 1; attribute = r->attribute; len = r->count; if (asel == SELECT_META_ATTRIBUTE) { attribute = r->meta_attribute; len = r->meta_count; } if (k == NULL) { /* check all attributes for this value */ for (i = 0; i < len; i++) { if (dsattribute_index(attribute[i], v) != IndexNull) return 1; } return 0; } i = dsrecord_attribute_index(r, k, asel); if (i != IndexNull) { if (v == NULL) return 1; if (dsattribute_index(attribute[i], v) != IndexNull) return 1; } return 0; } /* * Test a record against a pattern. * Returns 1 for match, 0 for no match. */ int dsrecord_match(dsrecord *r, dsrecord *pattern) { u_int32_t i, x; dsattribute *pa, *ra; if (r == pattern) return 1; if (r == NULL) return 0; if (pattern == NULL) return 1; /* check each attribute in the pattern */ for (i = 0; i < pattern->count; i++) { pa = pattern->attribute[i]; x = dsrecord_attribute_index(r, pa->key, SELECT_ATTRIBUTE); if (x == IndexNull) return 0; ra = r->attribute[x]; if (dsattribute_match(ra, pa) == 0) return 0; } /* check each meta-attribute in the pattern */ for (i = 0; i < pattern->meta_count; i++) { pa = pattern->meta_attribute[i]; x = dsrecord_attribute_index(r, pa->key, SELECT_META_ATTRIBUTE); if (x == IndexNull) return 0; ra = r->meta_attribute[x]; if (dsattribute_match(ra, pa) == 0) return 0; } return 1; } /* * Match just attributes or just meta-attributes */ int dsrecord_match_select(dsrecord *r, dsrecord *pattern, u_int32_t asel) { u_int32_t i, x, count; dsattribute *pa, *ra; if (r == pattern) return 1; if (r == NULL) return 0; if (pattern == NULL) return 1; /* check each (meta)attribute in the pattern */ count = 0; if (asel == SELECT_ATTRIBUTE) count = pattern->count; else count = pattern->meta_count; for (i = 0; i < count; i++) { pa = NULL; if (asel == SELECT_ATTRIBUTE) pa = pattern->attribute[i]; else pa = pattern->meta_attribute[i]; x = dsrecord_attribute_index(r, pa->key, asel); if (x == IndexNull) return 0; ra = NULL; if (asel == SELECT_ATTRIBUTE) ra = r->attribute[x]; else ra = r->meta_attribute[x]; if (dsattribute_match(ra, pa) == 0) return 0; } return 1; } int dsrecord_equal(dsrecord *a, dsrecord *b) { u_int32_t i, x; dsattribute *aa, *ba; if (a == b) return 1; if (a == NULL) return 0; if (b == NULL) return 0; if (a->count != b->count) return 0; /* check each attribute in a */ for (i = 0; i < a->count; i++) { aa = a->attribute[i]; x = dsrecord_attribute_index(b, aa->key, SELECT_ATTRIBUTE); if (x == IndexNull) return 0; ba = b->attribute[x]; if (dsattribute_equal(aa, ba) == 0) return 0; } /* check each meta-attribute in a */ for (i = 0; i < a->meta_count; i++) { aa = a->meta_attribute[i]; x = dsrecord_attribute_index(b, aa->key, SELECT_META_ATTRIBUTE); if (x == IndexNull) return 0; ba = b->meta_attribute[x]; if (dsattribute_equal(aa, ba) == 0) return 0; } return 1; }