## Example of Backing Store Use

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);

}