1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
 ss_pers_t *
 ss_pers_find(ss_scope_t *scope,                 /* Scope to be searched */
              ss_pers_t *key,                    /* Value for which to search. This is required even if MASK is null because
                                                  * the KEY determines the type of objects for which to search. */
              ss_persobj_t *mask,                /* Which elements of KEY to consider when searching. It is an error if no bits
                                                  * of MASK are set, but if MASK is the null pointer then KEY is assumed to
                                                  * match every object. If non-null then MASK and KEY must be of the same
                                                  * type. The reason MASK is an object pointer rather than an object link is
                                                  * that the memory is really only used to store one-byte flags that control
                                                  * how the matching is performed. In other words, MASK isn't truly an
                                                  * object--it just has to be the same size as an object. */
              size_t nskip,                      /* Number of initial matched results that should be skipped. */
              size_t *nfound,                    /* INOUT:  The input value limits the matching to the specified number of
                                                  * objects, and on successful return this points to the number of objects
                                                  * actually found to match. This can be a null pointer as long as BUFFER is
                                                  * a null pointer, but if BUFFER is supplied then the incoming value of NFOUND
                                                  * indicates the number of elements in BUFFER. An incoming value of SS_NOSIZE
                                                  * indicates that the result is not to be truncated. */
              ss_pers_t *buffer,                 /* Optional buffer to fill in with handles to items that were found. If this
                                                  * is the constant SS_PERS_TEST then this function behaves exactly as if the
                                                  * caller had supplied a buffer but does not attempt to return links to the
                                                  * matching objects. */
              ss_prop_t *props                   /* Optional properties (See Persistent Object Properties) */
              )
 {
     SS_ENTER(ss_pers_find, ss_pers_tP);
     unsigned tableid;
     ss_table_t *table=NULL;
     ss_pers_find_t find_data;
     ss_scope_t *reg_scope=NULL;
     size_t regidx;
     int noregistries=0;
     ss_gfile_t *gfile=NULL;

     memset(&find_data, 0, sizeof find_data);    /* Necessary for error cleanup */

     SS_ASSERT_MEM(scope, ss_scope_t);
     SS_ASSERT_CLASS(key, ss_pers_t);
     if (buffer && NULL==nfound)
         SS_ERROR_FMT(USAGE, ("if BUFFER is specified then NFOUND must be non-null"));

     tableid = SS_MAGIC_SEQUENCE(SS_MAGIC_OF(key));
     if (NULL==(table = ss_scope_table(scope, tableid, NULL))) SS_ERROR(FAILED);

     /* Initialize data to pass through ss_table_scan() */
     if (NULL==(find_data.key = ss_pers_deref(key))) SS_ERROR(NOTFOUND);
     find_data.mask = mask;
     find_data.buffer = buffer;
     find_data.nalloc = buffer ? *nfound : 0;
     find_data.limit = nfound ? *nfound : SS_NOSIZE;
     find_data.nskip = nskip;
     find_data.overflowed = FALSE;
     find_data.scope = scope;
     if (NULL==ss_prop_get(props, "detect_overflow", H5T_NATIVE_INT, &(find_data.detect_overflow))) {
         SS_STATUS_OK;
         find_data.detect_overflow = FALSE;
     }

     /* Scan the entire table for matches. We could also check whether ss_table_scan() returned positive, which indicates that
      * we've found more matches than the find_data.limit value. */
     if (ss_table_scan(table, NULL, 0, ss_pers_find_cb, &find_data)<0) SS_ERROR(FAILED);
     if (find_data.detect_overflow && find_data.overflowed) SS_ERROR(OVERFLOW);

     /* Search registries until we find something. The tables that describe the file infrastructure do not need to search
      * registries because doing so doesn't really make any sense: Scope, File, and Blob tables. */
     if (0==find_data.nused &&
         SS_MAGIC_OF(key)!=SS_MAGIC(ss_scope_t) &&
         SS_MAGIC_OF(key)!=SS_MAGIC(ss_file_t) &&
         SS_MAGIC_OF(key)!=SS_MAGIC(ss_blob_t) &&
         (NULL==ss_prop_get(props, "noregistries", H5T_NATIVE_INT, &noregistries) || !noregistries)) {
         SS_STATUS_OK; /*clean up from possible failed ss_prop_get()*/
         if (NULL==(gfile = SS_GFILE_LINK(scope))) SS_ERROR(FAILED);
         for (regidx=0; 0==find_data.nused && regidx<gfile->reg_nused; regidx++) {
             reg_scope = gfile->reg + regidx;
             if (NULL==(table = ss_scope_table(reg_scope, tableid, NULL))) SS_ERROR(FAILED);
             find_data.scope = reg_scope;
             if (ss_table_scan(table, reg_scope, 0, ss_pers_find_cb, &find_data)<0) SS_ERROR(FAILED);
             if (find_data.detect_overflow && find_data.overflowed) SS_ERROR(OVERFLOW);
         }
     }

     /* If no matches were found but we were otherwise successful then make sure we return a non-null value */
     if (nfound) *nfound = find_data.nused;
     if (0==find_data.nused && NULL==find_data.buffer) {
         find_data.buffer = calloc(1, sizeof(ss_pers_t));
         find_data.nalloc = 1;
     }

     /* If there is room then set the link after the last one to null */
     if (!buffer) SS_EXTEND(find_data.buffer, find_data.nused+1, find_data.nalloc);
     if (find_data.nused<find_data.nalloc && SS_PERS_TEST!=find_data.buffer)
         memset(find_data.buffer + find_data.nused, 0, sizeof(find_data.buffer[0]));


 SS_CLEANUP:
     if (!buffer) SS_FREE(find_data.buffer);
     if (nfound) *nfound = 0;
     SS_LEAVE(find_data.buffer);
 }