1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77/*
78**
79**  NAME:
80**
81**      rpcddb.c
82**
83**  FACILITY:
84**
85**      RPC Daemon Basic Database Routines
86**
87**  ABSTRACT:
88**
89**      Hash table management, list management, context handle management,
90**      database concurrency control (lock/unlock) routines. Basic database
91**      open and update routine.
92**
93**
94*/
95
96#include <dce/ep.h>
97#include <dsm.h>
98
99#include <commonp.h>
100#include <com.h>
101
102#include <rpcdp.h>
103#include <rpcddb.h>
104
105typedef struct {
106    struct db           *db_handle;
107    db_list_type_t      list_type;
108    db_lists_t          *lp;
109    unsigned32          pass;
110}   db_contexth_t, *db_contexth_p_t;
111
112INTERNAL void list_add
113    (
114        db_list_t   *list,
115        db_list_t   *elp
116    );
117
118INTERNAL void list_remove
119    (
120        db_list_t   *list,
121        db_list_t   *elp
122    );
123
124INTERNAL boolean32 db_bad_context
125    (
126        struct db           *h,
127        ept_lookup_handle_t *entry_handle
128    );
129
130/*
131 * Setup the persistent database image.
132 * If no database exists on disk, create it.
133 */
134PRIVATE void db_open(h, database_file, version, status)
135struct db       *h;
136unsigned char   *database_file;
137unsigned32      version;
138error_status_t  *status;
139{
140    struct db_file_hdr  hdr;
141    error_status_t      tmp_st;
142
143    SET_STATUS_OK(status);
144
145    dsm_open(database_file, (dsm_handle_t *) &h->dsh, status);
146    if (STATUS_OK(status))
147    {
148        /* read and check the file header info */
149        dsm_get_info(h->dsh,&hdr,sizeof(hdr),status);
150        if (! STATUS_OK(status))
151        {
152            if (dflag) show_st("Error reading endpoint database", status);
153            db_to_ept_ecode(status);
154            return;
155        }
156
157        if (hdr.version != version)
158        {
159            /*  Bad database version
160             *  Close database
161             *  If earlier version, just delete database,
162             *  we'll try to create a new one later.
163             *  If later version, return an error
164             */
165            dsm_close((dsm_handle_t *) &h->dsh, &tmp_st);
166            h->dsh = NULL;
167
168            if (hdr.version < version)
169            {
170                remove((char *)database_file);
171            }
172            else
173            {
174                SET_STATUS(status, ept_s_database_invalid);
175                if (dflag) show_st("Newer persistent database version", status);
176                return;
177            }
178        }
179        else
180            h->object = hdr.object;
181    }
182    else
183    if (*status != dsm_err_open_failed)
184    {
185        /* file exists but couldn't open it */
186        if (dflag)
187            show_st("Error opening endpoint database", status);
188        db_to_ept_ecode(status);
189        return;
190    }
191
192    if (h->dsh == NULL)
193    {
194        /*  Create and initialize file
195         */
196        dsm_create(database_file, (dsm_handle_t *) &h->dsh, status);
197        if (! STATUS_OK(status))
198        {
199            if (dflag)
200                show_st("Error creating endpoint database", status);
201            db_to_ept_ecode(status);
202            return;
203        }
204
205        uuid_create(&h->object, &tmp_st);
206
207        hdr.version = version;
208        hdr.object = h->object;
209        dsm_set_info(h->dsh, &hdr, sizeof(hdr), status);
210        if (! STATUS_OK(status))
211        {
212            if (dflag)
213                show_st("Error writing to endpoint database", status);
214            db_to_ept_ecode(status);
215            return;
216        }
217    }
218
219    return;
220}
221
222/*  db_update_entry
223 *  Update an existing record in the disk copy
224 *  of a database.
225 *  DSM update is really a delete and add so
226 *  if the process crashes between dsm_detach
227 *  and dsm_write the record is lost.
228 *
229 *  dsm_detach marks an entry as free on disk, used
230 *  in volatile memory (so it won't be given out to anyone
231 *  else during this process's lifetime but it will be
232 *  lost in a crash)
233 */
234
235PRIVATE void db_update_entry(h, entp, status)
236struct db       *h;
237db_entry_p_t    entp;
238error_status_t  *status;
239{
240    dsm_detach(h->dsh, (void *)entp, status);
241    if (! STATUS_OK(status)) return;
242
243    dsm_write(h->dsh, (void *)entp, status);
244    if (! STATUS_OK(status)) return;
245}
246
247
248/*
249 *  Each entry is on 3 lists: the entry list (of all entries), a list that is
250 *  keyed by the entry's object uuid, and a list that is keyed by the entry's
251 *  interface uuid.  An entry's object list and interface list are accessed
252 *  via uuid hash into a hash table which marks the beginning of a list for
253 *  all uuids that hash to the same value.  Separate hash tables are used for
254 *  the object lists and the interface lists.
255 *
256 *  The entry lists are not stably stored.  They are recreated at startup
257 *  time.
258 *
259 *  A database's lists are accessed via its struct db.lists_mgmt field.
260 *  The lists contain forward and back pointers with the last entry on
261 *  a list having its fwd ptr = NULL.
262 *
263 *  The procedures that traverse lists (db_list_first, db_list_next) return a pointer
264 *  to the beginning of an entry (assuming that db_lists_t is at the beginning of
265 *  db_entry_t).  To get a pointer to the beginning of the entry, these procedures
266 *  subtract a pre-inited offset from the entry's object or interface list ptr.
267 */
268INTERNAL unsigned32  db_c_object_list_offset;
269INTERNAL unsigned32  db_c_interface_list_offset;
270
271PRIVATE void db_init_lists(h)
272struct db           *h;
273{
274    int             i;
275    db_lists_mgmt_t *lists_mgmt;
276    db_lists_t      lists;
277
278    lists_mgmt = &h->lists_mgmt;
279
280    lists_mgmt->entry_list.fwd = NULL;
281    lists_mgmt->entry_list.back = &lists_mgmt->entry_list;
282
283    for (i = 0; i < db_c_nbucket; i++)
284    {
285        lists_mgmt->object_table[i].fwd = NULL;
286        lists_mgmt->object_table[i].back = &lists_mgmt->object_table[i];
287        lists_mgmt->interface_table[i].fwd = NULL;
288        lists_mgmt->interface_table[i].back = &lists_mgmt->interface_table[i];
289    }
290
291    db_c_object_list_offset = ((char *) &lists.object_list) - ((char *) &lists.entry_list);
292    db_c_interface_list_offset = ((char *) &lists.interface_list) - ((char *) &lists.entry_list);
293}
294
295PRIVATE void db_lists_add(h, entp)
296struct db       *h;
297db_entry_t      *entp;
298{
299    db_list_add(&h->lists_mgmt.entry_list, db_c_entry_list, (db_lists_t *) entp);
300
301    db_htable_add(h->lists_mgmt.object_table, db_c_object_list, &entp->object,
302        (db_lists_t *) entp);
303
304    db_htable_add(h->lists_mgmt.interface_table, db_c_interface_list, &entp->interface.uuid,
305        (db_lists_t *) entp);
306}
307
308PRIVATE void db_lists_remove(h, entp)
309struct db       *h;
310db_entry_t      *entp;
311{
312    db_list_remove(&h->lists_mgmt.entry_list, db_c_entry_list, (db_lists_t *) entp);
313
314    db_htable_remove(h->lists_mgmt.object_table, db_c_object_list, &entp->object,
315        (db_lists_t *) entp);
316
317    db_htable_remove(h->lists_mgmt.interface_table, db_c_interface_list, &entp->interface.uuid,
318        (db_lists_t *) entp);
319}
320
321PRIVATE void db_htable_add(htable, table_type, id, entp)
322db_hash_table_t     htable;
323db_list_type_t      table_type;
324uuid_p_t            id;
325db_lists_t          *entp;
326{
327    unsigned16      bucket;
328    error_status_t  tmp_st;
329
330    bucket = uuid_hash(id, &tmp_st);
331
332    bucket = bucket % db_c_nbucket;
333
334    db_list_add(&htable[bucket], table_type, entp);
335}
336
337PRIVATE void db_htable_remove(htable, table_type, id, entp)
338db_hash_table_t     htable;
339db_list_type_t      table_type;
340uuid_p_t            id;
341db_lists_t          *entp;
342{
343    unsigned16      bucket;
344    error_status_t  tmp_st;
345
346    bucket = uuid_hash(id, &tmp_st);
347
348    bucket = bucket % db_c_nbucket;
349
350    db_list_remove(&htable[bucket], table_type, entp);
351}
352
353/*
354 *  Add an entry (entp) to the beginning of list.
355 *  The entry is being added to one of 3 lists
356 *  which is defined by list_type
357 */
358PRIVATE void db_list_add(list, list_type, entp)
359db_list_t           *list;
360db_list_type_t      list_type;
361db_lists_t          *entp;
362{
363    db_list_t       *elp;
364    error_status_t  tmp_st;
365
366    switch(list_type)
367    {
368        case db_c_entry_list:
369            elp = &entp->entry_list;
370            break;
371        case db_c_object_list:
372            elp = &entp->object_list;
373            break;
374        case db_c_interface_list:
375            elp = &entp->interface_list;
376            break;
377        default:
378            tmp_st = ept_s_database_invalid;
379            show_st("db_list_add -  bad list type", &tmp_st);
380            return;
381    }
382
383    list_add(list, elp);
384}
385
386PRIVATE void db_list_remove(list, list_type, entp)
387db_list_t           *list;
388db_list_type_t      list_type;
389db_lists_t          *entp;
390{
391    db_list_t       *elp;
392    error_status_t  tmp_st;
393
394    switch(list_type)
395    {
396        case db_c_entry_list:
397            elp = &entp->entry_list;
398            break;
399        case db_c_object_list:
400            elp = &entp->object_list;
401            break;
402        case db_c_interface_list:
403            elp = &entp->interface_list;
404            break;
405        default:
406            tmp_st = ept_s_database_invalid;
407            show_st("db_list_remove -  bad list type", &tmp_st);
408            return;
409    }
410
411    list_remove(list, elp);
412}
413
414/*
415 *  Add entry elp to the end of list
416 */
417INTERNAL void list_add(list, elp)
418db_list_t   *list;
419db_list_t   *elp;
420{
421    elp->fwd = NULL;
422    elp->back = list->back;
423
424    elp->back->fwd = elp;
425    list->back = elp;
426}
427
428/*  Remove entry elp from a list
429 */
430INTERNAL void list_remove(list, elp)
431db_list_t   *list;
432db_list_t   *elp;
433{
434    elp->back->fwd = elp->fwd;
435    if (elp->fwd != NULL)
436        elp->fwd->back = elp->back;
437    else
438        list->back = elp->back;         /* remove from end of list */
439
440    elp->fwd = NULL;
441    elp->back = NULL;
442}
443
444/*  Return a pointer to the first entry on list list_type
445 */
446PRIVATE db_lists_t *db_list_first(lists_mgmt, list_type, id)
447db_lists_mgmt_t     *lists_mgmt;
448db_list_type_t      list_type;
449uuid_p_t            id;
450{
451    unsigned16      bucket;
452    error_status_t  tmp_st;
453    db_list_t       *elp;
454    db_lists_t      *entp;
455
456    entp = NULL;
457
458    switch(list_type)
459    {
460        case db_c_entry_list:
461            entp = (db_lists_t *) lists_mgmt->entry_list.fwd;
462            break;
463        case db_c_object_list:
464            bucket = uuid_hash(id, &tmp_st);
465            bucket = bucket % db_c_nbucket;
466            elp = lists_mgmt->object_table[bucket].fwd;
467            if (elp != NULL)
468                entp = (db_lists_t *) (((char *) elp) - db_c_object_list_offset);
469            break;
470        case db_c_interface_list:
471            bucket = uuid_hash(id, &tmp_st);
472            bucket = bucket % db_c_nbucket;
473            elp = lists_mgmt->interface_table[bucket].fwd;
474            if (elp != NULL)
475                entp = (db_lists_t *) (((char *) elp) - db_c_interface_list_offset);
476            break;
477        default:
478            tmp_st = ept_s_database_invalid;
479            show_st("db_list_first -  bad list type", &tmp_st);
480            break;
481    }
482
483    return(entp);
484}
485
486/*  Return a pointer to the next entry (after xentp) on list list_type
487 */
488PRIVATE db_lists_t *db_list_next(list_type, xentp)
489db_list_type_t      list_type;
490db_lists_t          *xentp;
491{
492    db_list_t       *elp;
493    db_lists_t      *entp;
494    error_status_t  tmp_st;
495
496    entp = NULL;
497
498    switch(list_type)
499    {
500        case db_c_entry_list:
501            entp = (db_lists_t *) xentp->entry_list.fwd;
502            break;
503        case db_c_object_list:
504            elp = xentp->object_list.fwd;
505            if (elp != NULL)
506                entp = (db_lists_t *) (((char *) elp) - db_c_object_list_offset);
507            break;
508        case db_c_interface_list:
509            elp = xentp->interface_list.fwd;
510            if (elp != NULL)
511                entp = (db_lists_t *) (((char *) elp) - db_c_interface_list_offset);
512            break;
513        default:
514            tmp_st = ept_s_database_invalid;
515            show_st("db_list_next -  bad list type", &tmp_st);
516            break;
517    }
518
519    return(entp);
520}
521
522/*  Save context
523 *  epdb_lookup, fwd, map take an ept_entry_handle_t context handle
524 *  argument which supports iterative search of the database.  The list
525 *  type, list entry pointer, and pass number are saved so the search
526 *  can resume where it left off.
527 */
528PRIVATE void db_save_context(h, entry_handle, list_type, lp, pass)
529struct db           *h;
530ept_lookup_handle_t *entry_handle;
531db_list_type_t      list_type;
532db_lists_t          *lp;
533unsigned32          pass;
534{
535    db_contexth_t   *chp;
536    db_entry_t      *entp;
537
538    /*
539     *  If the entry list pointer is NULL assume that the
540     *  job is done - just delete the context (if one has been
541     *  established) and return
542     */
543    if (lp == NULL)
544    {
545        db_delete_context(h, entry_handle);
546        return;
547    }
548
549    /*  Check that context handle is ok
550     */
551    if (db_bad_context(h, entry_handle))
552        return;
553
554    /*  If the context already exists, decrement the number of
555     *  read references in the entry to which the old context
556     *  points; this context won't point to the entry any more.
557     *  If the context does not exist, malloc space for it.
558     *
559     *  Set chp and *entry_handle to the context's address.
560     */
561    if (*entry_handle != NULL)
562    {
563        chp = (db_contexth_t *) (*entry_handle);
564        entp = (db_entry_t *) chp->lp;
565        entp->read_nrefs--;
566    }
567    else
568    {
569        *entry_handle = (ept_lookup_handle_t *) malloc(sizeof(db_contexth_t));
570        if (*entry_handle == NULL)
571            return;
572        chp = (db_contexth_t *) (*entry_handle);
573    }
574
575    /*  Increment read ref count of the entry to which context will point.
576     *  Check for read refs overflow
577     */
578    entp = (db_entry_t *) lp;
579    entp->read_nrefs++;
580    if (entp->read_nrefs >= db_c_max_read_nrefs)
581    {
582        db_delete_context(h, entry_handle);
583        return;
584    }
585
586    /*  Save new context info
587     */
588    chp->db_handle = h;
589    chp->list_type = list_type;
590    chp->lp = lp;
591    chp->pass = pass;
592}
593
594PRIVATE void db_delete_context(h, entry_handle)
595struct db           *h;
596ept_lookup_handle_t *entry_handle;
597{
598    db_contexth_t   *chp;
599    db_entry_t      *entp;
600
601    if (db_bad_context(h, entry_handle) || (*entry_handle == NULL))
602        return;
603
604    chp = (db_contexth_t *) (*entry_handle);
605    entp = (db_entry_t *) chp->lp;
606    entp->read_nrefs--;
607
608    free(chp);
609
610    *entry_handle = NULL;
611}
612
613PRIVATE void db_get_context(h, entry_handle, list_type, lp, pass, status)
614struct db           *h;
615ept_lookup_handle_t *entry_handle;
616db_list_type_t      *list_type;
617db_lists_t          **lp;
618unsigned32          *pass;
619error_status_t      *status;
620{
621    db_contexth_t   *chp;
622
623    if (db_bad_context(h, entry_handle) || (*entry_handle == NULL))
624    {
625        SET_STATUS(status, ept_s_invalid_context);
626        return;
627    }
628
629    chp = (db_contexth_t *) *entry_handle;
630    *list_type = chp->list_type;
631    *lp = chp->lp;
632    *pass = chp->pass;
633
634    SET_STATUS_OK(status);
635}
636
637/*  Check whether this entry_handle's context
638 *  points to the dbase denoted by h.
639 *  Return true and status = ept_s_invalid_context
640 *  if entry_handle's db_handle field != h arg.
641 *  Otherwise return false.
642 */
643PRIVATE boolean32 db_different_context(h, entry_handle, status)
644struct db           *h;
645ept_lookup_handle_t *entry_handle;
646error_status_t      *status;
647{
648    db_contexth_t   *chp;
649
650    SET_STATUS_OK(status);
651
652    if (entry_handle == NULL)
653        return(false);
654
655    if (*entry_handle != NULL)
656    {
657        chp = (db_contexth_t *) *entry_handle;
658        if (chp->db_handle != h)
659        {
660            SET_STATUS(status, ept_s_invalid_context);
661            return(true);
662        }
663    }
664
665    return(false);
666}
667
668/*  return true if entry_handle is a "bad" context
669 *  handle - ie.
670 *      there's no place to pass the handle back
671 *          to the caller (ie. he really didn't want to
672 *          save context)
673 *      the context handle doesn't point to this database
674 *  return false if entry_handle appears to be ok
675 */
676INTERNAL boolean32 db_bad_context(h, entry_handle)
677struct db           *h;
678ept_lookup_handle_t *entry_handle;
679{
680    db_contexth_t   *chp;
681
682    if (entry_handle == NULL)
683        return(true);
684
685    if (*entry_handle != NULL)
686    {
687        chp = (db_contexth_t *) *entry_handle;
688        if (chp->db_handle != h)
689            return(true);
690    }
691
692    return(false);
693}
694
695
696/*
697 * Note that the rpcddb package must protect a database from
698 * concurrent access since there can be a call executor thread,
699 * a dg forward map callback thread, and a check server liveness
700 * thread.
701 */
702
703PRIVATE void db_lock(h)
704struct db *h;
705{
706    dcethread_mutex_lock_throw(&h->lock);
707}
708
709PRIVATE void db_unlock(h)
710struct db *h;
711{
712    dcethread_mutex_unlock_throw(&h->lock);
713}
714
715PRIVATE void db_init_lock(h)
716struct db *h;
717{
718    dcethread_mutex_init_throw(&h->lock, NULL);
719}
720
721
722/*  Map dsm error codes to ept error codes
723 */
724PRIVATE void db_to_ept_ecode(status)
725error_status_t  *status;
726{
727    switch ((int)*status)
728    {
729        case dsm_err_create_failed:
730            *status = ept_s_cant_create;
731            break;
732        case dsm_err_file_io_error:
733            *status = ept_s_update_failed;
734            break;
735        case dsm_err_open_failed:
736            *status = ept_s_cant_access;
737            break;
738        case dsm_err_version:
739            *status = ept_s_database_invalid;
740            break;
741        case dsm_err_no_memory:
742            *status = ept_s_no_memory;
743            break;
744        case dsm_err_duplicate_write:
745            *status = ept_s_update_failed;
746            break;
747        case dsm_err_header_too_long:
748            *status = ept_s_database_invalid;
749            break;
750        case dsm_err_no_more_entries:
751            *status = ept_s_not_registered;
752            break;
753        case dsm_err_invalid_handle:
754            *status = ept_s_cant_perform_op;
755            break;
756        case dsm_err_invalid_pointer:
757            *status = ept_s_cant_perform_op;
758            break;
759        case dsm_err_info_too_long:
760            *status = ept_s_cant_perform_op;
761            break;
762        case dsm_err_file_busy:
763            *status = ept_s_database_already_open;
764            break;
765        case dsm_err_invalid_marker:
766            *status = ept_s_cant_perform_op;
767            break;
768        default:
769            break;
770    }
771}
772