For a full example of backing store use, see the OSF DCE Application Development Guide - Introduction and Style Guide.
The following brief example shows a portion of a server that manages an office telephone directory. Following are the relevant structures, defined in an IDL file:
typedef struct phone_record_s_t {
[string,ptr] char *name;
[string,ptr] char *email;
[string,ptr] char *phone;
[string,ptr] char *office;
} phone_record_t;
typedef struct phone_record_array_s_t {
unsigned32 count;
[ptr,size_is(count)] phone_record_t *entry;
} phone_record_array_t;
typedef struct phone_data_s_t {
dce_db_header_t h;
phone_record_t ph;
} phone_data_t;
/*
* The following routine returns the entire contents of the
* directory from the backing store by using the iteration
* routines. First, the portion of the IDL file that
* defines the routine's RPC format:
*/
[idempotent] void entire_phone_book(
[in] handle_t h,
[out] phone_record_array_t *e_array,
[out] error_status_t *st
);
Next the routine itself, written in C:
/* global variables */
dce_db_handle__t db_h; /* handle to phonebook backing store */
/* Other routines are not shown here, including the routine
* that opened the backing store.
*/
void
entire_phone_book(
/* [in] */ handle_t h, /* For RPC, but not used
* here. An ACL check
* would use it. */
/* [out] */ phone_record_array_t *e_array,
/* [out] */ error_status_t *st
)
{
uuid_t *dbkey;
phone_data_t pd;
unsigned32 i;
error_status_t st2;
*st = error_status_ok;
/* Lock before starting work, so that the backing
* store does not change until after all the info
* has been returned.
*/
dce_db_lock(db_h, st);
/* Count the entries so enough storage can be allocated */
e_array->count = 0;
dce_db_inq_count(db_h, &e_array->count, st);
if (*st != error_status_ok) {
dce_fprintf(stderr, *st); /* or some other treatment */
dce_db_unlock(db_h, st);
return;
}
if (e_array->count == 0) { /* No items, nothing to do */
dce_db_unlock(db_h, st);
return;
}
/* Allocate the space for the output. */
e_array->entry = rpc_sm_allocate(
e_array->count*sizeof(e_array->entry[0]),st);
if (*st != rpc_s_ok) {
dce_fprintf(stderr, *st); /* or some other treatment */
return
}
dce_db_iter_start(db_h, st);
i = 0;
while (TRUE) {
/* Get the next key. */
dce_db_iter_next(db_h, &dbkey, st);
/* break when we've scanned the entire backing store */
if (*st == db_s_no_more) break;
/* Get the data associated with the next key. */
dce_db_fetch_by_uuid(db_h, dbkey, (void *)&pd, st);
if (*st != error_status_ok) {
dce_fprintf(stderr, *st);
/* Don't forget to stop iterating and unlock after
* an error. */
dce_db_iter_done(db_h, &st2);
dce_db_unlock(db_h, &st2);
return;
}
/* Stick the item into the array to be returned
* when done. */
e_array->entry[i].name = strdup(pd.ph.name);
e_array->entry[i].email = strdup(pd.ph.email);
e_array->entry[i].phone = strdup(pd.ph.phone);
e_array->entry[i].office = strdup(pd.ph.office);
i++;
/* The use of strdup( ) above is illustrative, but it
* is not correct within a server, because the
* allocated memory is never freed. Correct code
* would involve the use of rpc_sm_allocate( ).
*/
}
/* The iteration is finished. */
dce_db_iter_done(db_h, st);
dce_db_unlock(db_h, st);
}